<<<<<<< HEAD
module MIPS_top(
    input clk, rst,
    output [31:0] out 
);

// IF output signals wire
wire [31:0] Pcout4_f_IF;
wire [31:0] inst_f_IF;

// register IF/ID signals
wire [31:0] pc4_f_IFID, inst_f_IFID;

//**************
// ID output 
// hazard module
wire IFIDWait_f_hd;
wire PCwait_f_hd;
wire Detect_to_Control_f_hd;

// control signals
wire JRFlush_f_id, JFlush_f_id;            // Jump signals,work at ID
wire branch_beq_f_id, branch_bne_f_id;     // work at MEM
wire JALFlush_f_id;                   // work at WB
wire ALUSrc_f_id, RegDst_f_id;             // work at EX 
wire [2:0] ALUop_f_id;                // work at EX
wire SignSelect_f_id;
wire MemWrite_f_id, MeMRead_f_id;          // work at MEM   
wire RegWrite_f_id, MeMtoReg_f_id; 

// from regs
wire [31:0] ReadData_rs_f_reg, ReadData_rt_f_reg;

// Addr of J instruction
wire [31:0] JumpAddr_f_JAddr;

// extent of immediate 
wire [31:0] SignImme_f_Sign;
wire [31:0] ZeroExtend_f_sign;

// signals from ID/EX
wire beq_f_id_ex, bne_f_id_ex;     // work at MEM
wire JALFlush_f_id_ex;                        // work at WB
wire ALUSrc_f_id_ex, RegDst_f_id_ex;               // work at EX 
wire SignSelect_f_id_ex;
wire [2:0] ALUop_f_id_ex;                       // work at EX
wire MemWrite_f_id_ex, MeMRead_f_id_ex;            // work at MEM   
wire RegWrite_f_id_ex, MeMtoReg_f_id_ex;           // work at WB
wire [31:0] pc4_f_id_ex;                        // pc+4
wire [31:0] inst_f_id_ex;                       // instruction
wire [31:0] Ext_imm_f_id_ex;                    //sign extend value
wire [31:0] Ext_zero_f_id_ex;
wire [31:0] Data_rs_f_id_ex, Data_rt_f_id_ex;             // data from regs 
wire [31:0] JalAddr_f_id_ex;

//**********************
// EX part
wire [31:0] pc8_f_ex;
wire [31:0] AddrBranch_f_ex;

// alu 
wire [31:0] alu1, alu2_1, alu2_2 ,alu2_sign_mux;
wire [1:0] ForwardA_f_forward, ForwardB_f_forward;

wire [31:0] rd_f_alu;  //more generally, it is just ALUout
wire Zero_f_alu; 
wire overflow_f_alu;
wire [4:0] rd_f_mux;

// ex/mem
wire beq_f_ex_mem, bne_f_ex_mem;                  // work at MEM
wire JALFlush_f_ex_mem;                          // work at WB
wire MemWrite_f_ex_mem, MeMRead_f_ex_mem;           // work at MEM   
wire RegWrite_f_ex_mem, MeMtoReg_f_ex_mem;          // work at WB
wire [31:0] JalAddr_f_ex_mem;                 // work at WB    
wire [31:0] pc8_f_ex_mem;                     // work at WB    
wire [4:0]  rd_f_ex_mem;                      // work at WB
wire  overflow_f_ex_mem;                      // work at WB
wire  zero_f_ex_mem;                          // work at MEM
wire [31:0] BranchAddr_f_ex_mem;              // address of bne,beq,work at MEM
wire [31:0] Res_f_ex_mem;                     // work at MEM
wire [31:0] Data_rt_f_ex_mem;

//****************
// mem

wire Pcscr_f_mem;
wire [31:0] rdata_f_dcache;

// mem_wb
wire JALFlush_f_mem_wb;                            // work at WB  
wire RegWrite_f_mem_wb, MeMtoReg_f_mem_wb;          // work at WB
wire [31:0] JalAddr_f_mem_wb;                 // work at WB    
wire [31:0] pc8_f_mem_wb;                     // work at WB    
wire [4:0]  rd_f_mem_wb;                      // work at WB
wire [31:0] Res_f_mem_wb;                     // work at WB
wire  overflow_f_mem_wb;                      // work at WB
wire [31:0] Data_f_mem_wb;

//***************
// wb
wire Regwrite_f_wb;
wire JALFlush_f_wb;
wire [31:0] JalAddr_f_wb;
wire [31:0] wb_data_f_wb;
wire [4:0] wb_addr_f_wb;

assign out = Res_f_ex_mem;

IF uut_if(
    .clk(clk), .rst(rst),
    .jr_from_id(JRFlush_f_id), 
    .j_from_id(JFlush_f_id), 
    .Pcscr_from_mem(Pcscr_f_mem), 
    .jal_from_wb(JALFlush_f_wb),
    .JrAddr_f_id(ReadData_rs_f_reg), 
    .JAddr_f_id(JumpAddr_f_JAddr), 
    .JalAddr_f_wb(JalAddr_f_wb), 
    .PscrAddr_f_mem(BranchAddr_f_ex_mem),
    .PCwait(PCwait_f_hd),
    .inst(inst_f_IF),
    .PCout4(Pcout4_f_IF)    
);

IFID uut_ifid(
    .clk(clk), .rst(rst), 
    .IFIDFlush(1'b0),                           // IFIDFlush clear signals
    .IFIDWait(IFIDWait_f_hd),                   // IFIDWait keep signals
    .JRFlush_from_ID(JRFlush_f_id),
    .JFlush_from_ID(JFlush_f_id),
    .JALFlush_from_WB(JALFlush_f_wb),
    .PCScr(Pcscr_f_mem),
    .inst_from_IF(inst_f_IF),                           // current instruction
    .pc4_form_IF(Pcout4_f_IF),                             // next pc value
    .pc4_to_ID(pc4_f_IFID), 
    .inst_to_ID(inst_f_IFID)
);
HazardDetext uut_hd(
    .MeMRead_from_ID_EX(MeMRead_f_id_ex),
    .rt_from_ID_EX(inst_f_id_ex[20:16]),
    .rs_from_IF_ID(inst_f_IFID[25:21]), 
    .rt_from_IF_ID(inst_f_IFID[20:16]),
    .IFIDWait(IFIDWait_f_hd), 
    .PCwait(PCwait_f_hd), 
    .Detect_to_Control(Detect_to_Control_f_hd)
);
MIPSControl uut_control(
    .inst_from_IF_ID(inst_f_IFID),
    .clk(clk), .rst(rst),
    .Detect_to_Control(Detect_to_Control_f_hd),               // clear signals when it is true
    
    .JRFlush(JRFlush_f_id), 
    .JFlush(JFlush_f_id),            // Jump signals,work at ID
    .branch_beq(branch_beq_f_id), 
    .branch_bne(branch_bne_f_id),     // work at MEM
    .JALFlush(JALFlush_f_id),                   // work at WB

    .ALUSrc(ALUSrc_f_id), 
    .RegDst(RegDst_f_id),             // work at EX 
    .ALUop(ALUop_f_id),                // work at EX
    .MemWrite(MemWrite_f_id), 
    .MeMRead(MeMRead_f_id),          // work at MEM   
    .RegWrite(RegWrite_f_id), 
    .MeMtoReg(MeMtoReg_f_id),          // work at WB
    .SignSelect(SignSelect_f_id)
);
Regs uut_regs(
    .clk(clk), .rst(rst), 
    .RegWrite(Regwrite_f_wb),
    .ReadAddr_rs(inst_f_IFID[25:21]), 
    .ReadAddr_rt(inst_f_IFID[20:16]),
    .WriteAddr_rd(wb_addr_f_wb),              //需要注意的是不同指令可能名称不同
    .WriteData(wb_data_f_wb),
    .ReadData_rs(ReadData_rs_f_reg), 
    .ReadData_rt(ReadData_rt_f_reg) 
);
IdJumpAddr uut_idjumpAddr(
    .instr_index_of_inst(inst_f_IFID[25:0]),
    .Pc4_from_IF_ID(pc4_f_IFID),
    .JumpAddr_to_IF(JumpAddr_f_JAddr)
);
SignExtend uut_sign(
    .imme_of_inst(inst_f_IFID[15:0]),
    .SignImme(SignImme_f_Sign),
    .ZeroExtend(ZeroExtend_f_sign)
);
IDEX uut_idex(
    .clk(clk), .rst(rst), 
    .JALFlush_from_WB(JALFlush_f_wb),   // flush IDEX regiater
    .PCScr_from_MEM(Pcscr_f_mem),

    // control signals
    .branch_beq_from_ID(branch_beq_f_id), 
    .branch_bne_from_ID(branch_bne_f_id),      // work at MEM
    .JALFlush_from_ID(JALFlush_f_id),                            // work at WB

    .ALUSrc_from_ID(ALUSrc_f_id), 
    .RegDst_from_ID(RegDst_f_id),              // work at EX 
    .ALUop_from_ID(ALUop_f_id),                         // work at EX
    .SignSelect_from_ID(SignSelect_f_id),                    //////////////////////
    .MemWrite_from_ID(MemWrite_f_id), 
    .MeMRead_from_ID(MeMRead_f_id),           // work at MEM   
    .RegWrite_from_ID(RegWrite_f_id), 
    .MeMtoReg_from_ID(MeMtoReg_f_id),          // work at WB
    // data
    .pc4_from_ID(pc4_f_IFID),                  // pc+4
    .inst_from_ID(inst_f_IFID),                 // instruction
    .Ext_imm_from_ID(SignImme_f_Sign),              //sign extend value
    .Ext_zero_from_ID(ZeroExtend_f_sign),
    .Data_from_rs(ReadData_rs_f_reg), 
    .Data_from_rt(ReadData_rt_f_reg),   // data from regs 
    .JalAddr_from_ID(JumpAddr_f_JAddr),                 //work at WB

    // output
    .branch_beq_2_EX(beq_f_id_ex), 
    .branch_bne_2_EX(bne_f_id_ex),     // work at MEM
    .JALFlush_2_EX(JALFlush_f_id_ex),                        // work at WB

    .ALUSrc_2_EX(ALUSrc_f_id_ex), 
    .RegDst_2_EX(RegDst_f_id_ex),               // work at EX 
    .ALUop_2_EX(ALUop_f_id_ex),                       // work at EX
    .SignSelect_2_EX(SignSelect_f_id_ex),
    .MemWrite_2_EX(MemWrite_f_id_ex), 
    .MeMRead_2_EX(MeMRead_f_id_ex),            // work at MEM   
    .RegWrite_2_EX(RegWrite_f_id_ex), 
    .MeMtoReg_2_EX(MeMtoReg_f_id_ex),           // work at WB

    .pc4_2_EX(pc4_f_id_ex),                        // pc+4
    .inst_2_EX(inst_f_id_ex),                       // instruction
    .Ext_imm_2_EX(Ext_imm_f_id_ex),                    //sign extend value
    .Ext_zero_2_EX(Ext_zero_f_id_ex),
    .Data_2_rs(Data_rs_f_id_ex), 
    .Data_2_rt(Data_rt_f_id_ex),             // data from regs 
    .JalAddr_2_EX(JalAddr_f_id_ex)
);

//******************
// EX part
// bne, beq address generate and back up pc8 for jal
AddrGenerate uut_jal_branch(
    .pc4_from_ID_EX(pc4_f_id_ex),
    .Ext_imm_from_ID_EX(Ext_imm_f_id_ex),
    .pc8_EX(pc8_f_ex),
    .AddrBranch(AddrBranch_f_ex)            //Address of bne,beq
);
// ALU 
// mux at input 1 of alu
mux3 uut_mux_in1_alu(
    .in0(Data_rs_f_id_ex), 
    .in1(wb_data_f_wb), 
    .in2(Res_f_ex_mem),
    .choose(ForwardA_f_forward),
    .lucky(alu1)
);
mux3 uut_mux_in2_alu(
    .in0(Data_rt_f_id_ex), 
    .in1(wb_data_f_wb), 
    .in2(Res_f_ex_mem),
    .choose(ForwardB_f_forward),
    .lucky(alu2_1)
);
mux2 uut_mux2_alu(
    .in0(alu2_1), 
    .in1(alu2_sign_mux),
    .choose(ALUSrc_f_id_ex),
    .lucky(alu2_2)
);
mux2 uut_mux_sign(           // rt, decide the signed_extend or zero_extend
    .in0(Ext_zero_f_id_ex), 
    .in1(Ext_imm_f_id_ex),
    .choose(SignSelect_f_id_ex),
    .lucky(alu2_sign_mux)
);
ALU uut_alu(
    .rs(alu1),  //也作为访存指令中的base
    .rt(alu2_2),
    .sa(inst_f_id_ex[10:6]),   // ins[10:6] of R type    
    .ALUop(ALUop_f_id_ex),
    .FuncCode(inst_f_id_ex[5:0]),
    .rd(rd_f_alu),  //more generally, it is just ALUout
    .Zero(Zero_f_alu), 
    .overflow(overflow_f_alu)
);
mux2_5 uut_wbAddrSelect(
    .in0(inst_f_id_ex[20:16]),    // rt
    .in1(inst_f_id_ex[15:11]),    // rd
    .choose(RegDst_f_id_ex),
    .lucky(rd_f_mux)
);
Forward uut_forward(
    .rt_from_ID_EX(inst_f_id_ex[20:16]), 
    .rs_from_ID_EX(inst_f_id_ex[25:21]),
    .rd_from_EX_MEM(rd_f_ex_mem), 
    .rd_from_MEM_WB(rd_f_mem_wb),
    .EX_MEM_RegWrite(RegWrite_f_ex_mem), 
    .MEM_WB_RegWrite(RegWrite_f_mem_wb),
    .ForwardA(ForwardA_f_forward), 
    .ForwardB(ForwardB_f_forward)
);
EXMEM uut_ex_mem(
    .clk(clk),.rst(rst),
    .JALFlush_from_WB(JALFlush_f_wb),   // flush IDEX regiater
    .PCScr_from_MEM(Pcscr_f_mem),

    // control signals
    .branch_beq_from_EX(beq_f_id_ex), 
    .branch_bne_from_EX(bne_f_id_ex),      // work at MEM
    .JALFlush_from_EX(JALFlush_f_id_ex),                            // work at WB

    .MemWrite_from_EX(MemWrite_f_id_ex), 
    .MeMRead_from_EX(MeMRead_f_id_ex),           // work at MEM   
    .RegWrite_from_EX(RegWrite_f_id_ex), 
    .MeMtoReg_from_EX(MeMtoReg_f_id_ex),          // work at WB
    
    // data
    .JalAddr_from_EX(JalAddr_f_id_ex),                 // work at WB    
    .pc8_from_Ex(pc8_f_ex),                     // work at WB    
    .rd_from_mux(rd_f_mux),                     // work at WB
    .overflow_from_ALU(overflow_f_alu),                     // work at WB
    .zero_from_ALU(Zero_f_alu),                         // work at MEM
    .BranchAddr_from_EX(AddrBranch_f_ex),              // address of bne,beq,work at MEM
    .Res_from_ALU(rd_f_alu),                    // work at MEM
    .Data_rt_from_EX(alu2_1),                 // work at MEM, to Dcache
    
    // out     
    .beq_2_MEM(beq_f_ex_mem), 
    .bne_2_MEM(bne_f_ex_mem),                  // work at MEM
    .JALFlush_2_MEM(JALFlush_f_ex_mem),
    .MemWrite_2_MEM(MemWrite_f_ex_mem), 
    .MeMRead_2_MEM(MeMRead_f_ex_mem),           // work at MEM   
    .RegWrite_2_MEM(RegWrite_f_ex_mem), 
    .MeMtoReg_2_MEM(MeMtoReg_f_ex_mem),          // work at WB
    .JalAddr_2_MEM(JalAddr_f_ex_mem),                 // work at WB    
    .pc8_2_MEM(pc8_f_ex_mem),                     // work at WB    
    .rd_2_MEM(rd_f_ex_mem),                      // work at WB
    .overflow_2_MEM(overflow_f_ex_mem),                      // work at WB
    .zero_2_MEM(zero_f_ex_mem),                          // work at MEM
    .BranchAddr_2_MEM(BranchAddr_f_ex_mem),              // address of bne,beq,work at MEM
    .Res_2_MEM(Res_f_ex_mem),                     // work at MEM
    .Data_rt_2_MEM(Data_rt_f_ex_mem)                  // work at MEM, to Dcache
);

//*************
// MEM
PCscr uut_pcscr(
    .bne_EX_MEM(bne_f_ex_mem), 
    .beq_EX_MEM(beq_f_ex_mem),
    .zero_EX_MEM(zero_f_ex_mem),
    .Pcscr(Pcscr_f_mem)
);
dcache uut_dcache(
    .clk(clk),.reset(rst),
    .we(MemWrite_f_ex_mem),
    .re(MeMRead_f_ex_mem),
    .addr(Res_f_ex_mem),
    .wdata(Data_rt_f_ex_mem),
    .rdata(rdata_f_dcache)
);
MEMWB uut_mem_wb(
    .clk(clk), .rst(rst),
    .JALFlush_from_WB(JALFlush_f_wb),   // flush IDEX regiater
    // control signals    
    .JALFlush_from_MEM(JALFlush_f_ex_mem),                            // work at WB  
    .RegWrite_from_MEM(RegWrite_f_ex_mem), 
    .MeMtoReg_from_MEM(MeMtoReg_f_ex_mem),          // work at WB
    
    // data
    .JalAddr_from_MEM(JalAddr_f_ex_mem),                 // work at WB    
    .pc8_from_MEM(pc8_f_ex_mem),                     // work at WB    
    .rd_from_MEM(rd_f_ex_mem),                      // work at WB
    .Res_from_MEM(Res_f_ex_mem),                     // work at WB
    .overflow_from_MEM(overflow_f_ex_mem),                      // work at WB
    .Data_from_dcache(rdata_f_dcache),                 // work at WB

    // out
    .JALFlush_2_WB(JALFlush_f_mem_wb),                            // work at WB  
    .RegWrite_2_WB(RegWrite_f_mem_wb), 
    .MeMtoReg_2_WB(MeMtoReg_f_mem_wb),          // work at WB
    
    // data
    .JalAddr_2_WB(JalAddr_f_mem_wb),                 // work at WB    
    .pc8_2_WB(pc8_f_mem_wb),                     // work at WB    
    .rd_2_WB(rd_f_mem_wb),                      // work at WB
    .Res_2_WB(Res_f_mem_wb),                     // work at WB
    .overflow_2_WB(overflow_f_mem_wb),                      // work at WB
    .Data_2_WB(Data_f_mem_wb)                  // work at WB    
);
WB uut_wb(
    // control signals    
    .JALFlush_from_MEM_WB(JALFlush_f_mem_wb),                            // work at WB  
    .RegWrite_from_MEM_WB(RegWrite_f_mem_wb), 
    .MeMtoReg_from_MEM_WB(MeMtoReg_f_mem_wb),          // work at WB
    
    // data
    .JalAddr_from_MEM_WB(JalAddr_f_mem_wb),                 // work at WB    
    .pc8_from_MEM_WB(pc8_f_mem_wb),                     // work at WB    
    .rd_from_MEM_WB(rd_f_mem_wb),                      // work at WB
    .Res_from_MEM_WB(Res_f_mem_wb),                     // work at WB
    .overflow_from_MEM_WB(overflow_f_mem_wb),                      // work at WB
    .Data_from_MEM_WB(Data_f_mem_wb),                 // work at WB

    .Regwrite_2_regs(Regwrite_f_wb),
    .JALFlush_2_IF(JALFlush_f_wb),
    .JalAddr_2_IF(JalAddr_f_wb),
    .wb_data(wb_data_f_wb),
    .wb_addr(wb_addr_f_wb)
);

endmodule

//
// Instruction Fetch
//
module IF(
    input clk, rst,
    input jr_from_id, j_from_id, Pcscr_from_mem, jal_from_wb,
    input [31:0] JrAddr_f_id, JAddr_f_id, JalAddr_f_wb, PscrAddr_f_mem,
    input PCwait,
    output [31:0] inst,
    output [31:0] PCout4    
);
// wire form if
wire [31:0] pc_mux_reg;
wire [31:0] pc4_reg_mux;
wire [31:0] PCout;

assign PCout4 = pc4_reg_mux;
pcmux uut_pcmux(
    .jr(jr_from_id), .j(j_from_id), .Pcscr(Pcscr_from_mem), .jal(jal_from_wb),
    .pc4(pc4_reg_mux), .JrAddr(JrAddr_f_id), .JAddr(JAddr_f_id), .JalAddr(JalAddr_f_wb),
    .PscrAddr(PscrAddr_f_mem), .CurrentPC(pc_mux_reg)
);
PCreg uut_PCreg(
    .clk(clk), .rst(rst),
    .PCwait(PCwait),       //keep the PC value when pipeline stall
    .PCin(pc_mux_reg),
    .PCout(PCout),
    .PCout4(pc4_reg_mux)
);
icache uut_ica(
	.rst(rst),
	.pc(PCout),
	.inst(inst)
);
endmodule

module pcmux(
    input jr, j, Pcscr, jal,
    input [31:0] pc4, JrAddr, JAddr, JalAddr, PscrAddr,
    output [31:0] CurrentPC
);
wire [31:0] w1, w2, w3;

assign w1 = (jr)? JrAddr:pc4;
assign w2 = (j)?  JAddr:w1;
assign w3 = (Pcscr)? PscrAddr:w2;
assign CurrentPC = (jal)? JalAddr:w3;
endmodule

module mux3(
    input [31:0] in0, in1, in2,
    input [1:0] choose,
    output reg[31:0] lucky
);
always@(*) begin
    case(choose)
         2'b00,2'b11: lucky <= in0;
         2'b01: lucky <= in1;
         2'b10: lucky <= in2;
    endcase
end
endmodule

module mux2(
    input [31:0] in0, in1,
    input choose,
    output [31:0] lucky
);
assign lucky = (choose)? in1:in0;
endmodule

module mux2_5(
    input [4:0] in0, in1,
    input choose,
    output [4:0] lucky
);
assign lucky = (choose)? in1:in0;
endmodule


module ALU(
    input [31:0] rs,  //也作为访存指令中的base
    input [31:0] rt,
    input [4:0] sa,   // ins[10:6] of R type    
    input [2:0] ALUop,
    input [5:0] FuncCode,
    output reg [31:0] rd,  //more generally, it is just ALUout
    output wire Zero, 
    output reg overflow
);

//这里溢出还需要解决，ADD和ADDi以及Sub都需要解决溢出
//不写入问题，如何控制溢出的信号？

reg [3:0] ALUCtl;

assign Zero = (rd==0); //zero is true if rd is 0

//Generate ALUCtl by ALUop form Control unit
always @(*)begin
case(ALUop)
   3'b000,3'b111:  ALUCtl <= 4'b0010;   // add   
   3'b001:  ALUCtl <= 4'b0110;   // sub
   3'b010:begin                  // R type
          case(FuncCode)
          6'b100000,6'b100001: ALUCtl <= 4'b0010;   // add
          6'b100010: ALUCtl <= 4'b0110;   // sub
          6'b100100: ALUCtl <= 4'b0000;   // and
          6'b100101: ALUCtl <= 4'b0001;   // or
          6'b100110: ALUCtl <= 4'b0100;   // xor
          6'b100111: ALUCtl <= 4'b1100;   // nor
          6'b101010: ALUCtl <= 4'b0111;   // slt
          6'b000000: ALUCtl <= 4'b0011;   // sll
          6'b000010: ALUCtl <= 4'b1000;   // srl
          default: ALUCtl <= 4'b1111;     // should not happen 
          endcase
   end
   3'b011: ALUCtl <= 4'b0001;   // or
   3'b100: ALUCtl <= 4'b0000;   // and
   3'b101: ALUCtl <= 4'b0100;   // xor
   3'b110: ALUCtl <= 4'b1110;   //lui
   default: ALUCtl <= 4'b1111;     // should not happen 
endcase
end

always @(*) begin
    case (ALUCtl)
    4'b0000: rd <= rs & rt;  //and
    4'b0001: rd <= rs | rt;  //or
    4'b0010: rd <= rs + rt;  //add
    4'b0100: rd <= rs ^ rt;  //xor
    4'b0110: rd <= rs - rt;  //sub
    4'b0111: rd <= rs < rt? 1:0;  //is ture if rs is smaller
    4'b1100: rd <= ~(rs | rt);    //result is nor
    4'b0011: rd <= rt << sa;      // left shift sa bit
    4'b1000: rd <= rt >> sa;      // right shift sa bit
    4'b1110: rd <= {rt[15:0],16'b0}; // Lui instruction
    default: rd <= 0;
    endcase
end

always@(*)begin
    case(ALUop)
    3'b010:begin
        case(FuncCode)
        6'b100000: overflow <= rd[31] ^ rd[30];   // add
        6'b100010: overflow <= rd[31] ^ rd[30];   // sub
        default: overflow <= 1'b0;
        endcase
    end
    3'b111: overflow <= rd[31] ^ rd[30];   //addi
    default:overflow <= 1'b0;
    endcase
end
endmodule

module AddrGenerate(
    input [31:0] pc4_from_ID_EX,
    input [31:0] Ext_imm_from_ID_EX,
    output [31:0] pc8_EX,
    output [31:0] AddrBranch            //Address of bne,beq
);
wire [31:0] shift;
assign shift = {Ext_imm_from_ID_EX[29:0],2'b0};    // left shift 2bit
assign AddrBranch = shift + pc4_from_ID_EX;
assign pc8_EX = pc4_from_ID_EX + 32'd4;
endmodule

module EXMEM(
    input clk,rst,
    input JALFlush_from_WB,   // flush IDEX regiater
    input PCScr_from_MEM,

    // control signals
    input branch_beq_from_EX, branch_bne_from_EX,      // work at MEM
    input JALFlush_from_EX,                            // work at WB

    input MemWrite_from_EX, MeMRead_from_EX,           // work at MEM   
    input RegWrite_from_EX, MeMtoReg_from_EX,          // work at WB
    
    // data
    input [31:0] JalAddr_from_EX,                 // work at WB    
    input [31:0] pc8_from_Ex,                     // work at WB    
    input [4:0]  rd_from_mux,                     // work at WB
    input  overflow_from_ALU,                     // work at WB
    input  zero_from_ALU,                         // work at MEM
    input [31:0] BranchAddr_from_EX,              // address of bne,beq,work at MEM
    input [31:0] Res_from_ALU,                    // work at MEM
    input [31:0] Data_rt_from_EX,                 // work at MEM, to Dcache
    
    // out     
    output reg beq_2_MEM, bne_2_MEM,                  // work at MEM
    output reg JALFlush_2_MEM,                          // work at WB

    output reg MemWrite_2_MEM, MeMRead_2_MEM,           // work at MEM   
    output reg RegWrite_2_MEM, MeMtoReg_2_MEM,          // work at WB

    output reg [31:0] JalAddr_2_MEM,                 // work at WB    
    output reg [31:0] pc8_2_MEM,                     // work at WB    
    output reg [4:0]  rd_2_MEM,                      // work at WB
    output reg  overflow_2_MEM,                      // work at WB
    output reg  zero_2_MEM,                          // work at MEM
    output reg [31:0] BranchAddr_2_MEM,              // address of bne,beq,work at MEM
    output reg [31:0] Res_2_MEM,                     // work at MEM
    output reg [31:0] Data_rt_2_MEM                  // work at MEM, to Dcache
);

always@(posedge clk or negedge rst)begin
    if(!rst)begin
        beq_2_MEM <= 1'b0; 
        bne_2_MEM <= 1'b0;                             // work at MEM
        JALFlush_2_MEM <= 1'b0;                          // work at WB

        MemWrite_2_MEM <= 1'b0; 
        MeMRead_2_MEM <= 1'b0;           // work at MEM   
        RegWrite_2_MEM <= 1'b0; 
        MeMtoReg_2_MEM <= 1'b0;          // work at WB

        JalAddr_2_MEM <= 32'd0;                 // work at WB    
        pc8_2_MEM <= 32'd0;                     // work at WB    
        rd_2_MEM <= 5'd0;                      // work at WB
        overflow_2_MEM <= 1'd0;                      // work at WB
        zero_2_MEM <= 1'd0;                          // work at MEM
        BranchAddr_2_MEM <= 32'd0;              // address of bne,beq,work at MEM
        Res_2_MEM <= 32'd0;                     // work at MEM
        Data_rt_2_MEM <= 32'd0;
    end
    else if(JALFlush_from_WB|PCScr_from_MEM)begin
        beq_2_MEM <= 1'b0; 
        bne_2_MEM <= 1'b0;                             // work at MEM
        JALFlush_2_MEM <= 1'b0;                          // work at WB

        MemWrite_2_MEM <= 1'b0; 
        MeMRead_2_MEM <= 1'b0;           // work at MEM   
        RegWrite_2_MEM <= 1'b0; 
        MeMtoReg_2_MEM <= 1'b0;          // work at WB

        JalAddr_2_MEM <= 32'd0;                 // work at WB    
        pc8_2_MEM <= 32'd0;                     // work at WB    
        rd_2_MEM <= 5'd0;                      // work at WB
        overflow_2_MEM <= 1'd0;                      // work at WB
        zero_2_MEM <= 1'd0;                          // work at MEM
        BranchAddr_2_MEM <= 32'd0;              // address of bne,beq,work at MEM
        Res_2_MEM <= 32'd0;                     // work at MEM
        Data_rt_2_MEM <= 32'd0;

    end
    else begin
        beq_2_MEM <= branch_beq_from_EX; 
        bne_2_MEM <= branch_bne_from_EX;                    // work at MEM
        JALFlush_2_MEM <= JALFlush_from_EX;                   // work at WB

        MemWrite_2_MEM <= MemWrite_from_EX; 
        MeMRead_2_MEM <= MeMRead_from_EX;                     // work at MEM   
        RegWrite_2_MEM <= RegWrite_from_EX; 
        MeMtoReg_2_MEM <= MeMtoReg_from_EX;                   // work at WB

        JalAddr_2_MEM <= JalAddr_from_EX;             // work at WB    
        pc8_2_MEM <= pc8_from_Ex;                     // work at WB    
        rd_2_MEM <= rd_from_mux;                      // work at WB
        overflow_2_MEM <= overflow_from_ALU;                  // work at WB
        zero_2_MEM <= zero_from_ALU;                          // work at MEM
        BranchAddr_2_MEM <= BranchAddr_from_EX;               // address of bne,beq,work at MEM
        Res_2_MEM <= Res_from_ALU;                     // work at MEM
        Data_rt_2_MEM <= Data_rt_from_EX;
    end
end
endmodule

module Forward(
    input [4:0] rt_from_ID_EX, rs_from_ID_EX,
    input [4:0] rd_from_EX_MEM, rd_from_MEM_WB,
    input EX_MEM_RegWrite, MEM_WB_RegWrite,
    output reg [1:0] ForwardA, ForwardB
);

wire EXDectA, EXDectB,MEMDectA, MEMDectB;

// forward A
assign EXDectA = EX_MEM_RegWrite 
                & (rd_from_EX_MEM!=5'd0)
                & (rd_from_EX_MEM == rs_from_ID_EX);
assign MEMDectA = MEM_WB_RegWrite 
                & (rd_from_MEM_WB != 5'd0)
                & (~EXDectA) 
                &(rd_from_MEM_WB==rs_from_ID_EX);
// forward B
assign EXDectB = EX_MEM_RegWrite 
                & (rd_from_EX_MEM!=5'd0)
                & (rd_from_EX_MEM == rt_from_ID_EX);
assign MEMDectB = MEM_WB_RegWrite 
                & (rd_from_MEM_WB != 5'd0)
                & (~EXDectB) 
                &(rd_from_MEM_WB==rt_from_ID_EX);

always@(*)begin
    if(EXDectA)begin
           ForwardA <= 2'b10;
    end
    else if(MEMDectA)begin
        ForwardA <= 2'b01;
    end 
    else ForwardA <= 2'b00;
end

always@(*)begin
    if(EXDectB)begin
           ForwardB <= 2'b10;
    end
    else if(MEMDectB)begin
        ForwardB <= 2'b01;
    end 
    else ForwardB <= 2'b00;
end
endmodule

module HazardDetext(
    input MeMRead_from_ID_EX,
    input [4:0] rt_from_ID_EX,
    input [4:0] rs_from_IF_ID, rt_from_IF_ID,
    output IFIDWait, PCwait, Detect_to_Control
);
wire Stall;
assign Stall = MeMRead_from_ID_EX
             &((rt_from_ID_EX==rs_from_IF_ID)|(rt_from_ID_EX==rt_from_IF_ID));

assign IFIDWait = (Stall)? 1'b1:1'b0;
assign PCwait = (Stall)? 1'b1:1'b0;     
assign Detect_to_Control = (Stall)? 1'b1:1'b0;
endmodule

module IDEX(
    input clk, rst, 
    input JALFlush_from_WB,   // flush IDEX regiater
    input PCScr_from_MEM,

    // control signals
    input branch_beq_from_ID, branch_bne_from_ID,      // work at MEM
    input JALFlush_from_ID,                            // work at WB

    input ALUSrc_from_ID, RegDst_from_ID,              // work at EX 
    input [2:0] ALUop_from_ID,                         // work at EX
    input SignSelect_from_ID,
    input MemWrite_from_ID, MeMRead_from_ID,           // work at MEM   
    input RegWrite_from_ID, MeMtoReg_from_ID,          // work at WB
    // data
    input [31:0] pc4_from_ID,                  // pc+4
    input [31:0] inst_from_ID,                 // instruction
    input [31:0] Ext_imm_from_ID,              //sign extend value
    input [31:0] Ext_zero_from_ID,
    input [31:0] Data_from_rs, Data_from_rt,   // data from regs 
    input [31:0] JalAddr_from_ID,                 //work at WB

    // output
    output reg branch_beq_2_EX, branch_bne_2_EX,     // work at MEM
    output reg JALFlush_2_EX,                        // work at WB

    output reg ALUSrc_2_EX, RegDst_2_EX,               // work at EX 
    output reg [2:0] ALUop_2_EX,                       // work at EX
    output reg SignSelect_2_EX,                             // work at EX

    output reg MemWrite_2_EX, MeMRead_2_EX,            // work at MEM   
    output reg RegWrite_2_EX, MeMtoReg_2_EX,           // work at WB

    output reg [31:0] pc4_2_EX,                        // pc+4
    output reg [31:0] inst_2_EX,                       // instruction
    output reg [31:0] Ext_imm_2_EX,                    //sign extend value
    output reg [31:0] Ext_zero_2_EX,
    output reg [31:0] Data_2_rs, Data_2_rt,             // data from regs 
    output reg [31:0] JalAddr_2_EX
);

always@(posedge clk or negedge rst)begin
    if(!rst)begin
        branch_beq_2_EX <= 1'b0; 
        branch_bne_2_EX <= 1'b0;     
        JALFlush_2_EX <= 1'b0;        // branch instruction

        ALUSrc_2_EX <= 1'b0;
        RegDst_2_EX <= 1'b0; 
        SignSelect_2_EX <= 1'b0;                    
        MemWrite_2_EX <= 1'b0; 
        MeMRead_2_EX <= 1'b0;            
        RegWrite_2_EX <= 1'b0; 
        MeMtoReg_2_EX <= 1'b0;
        pc4_2_EX <= 32'd0;                  
        inst_2_EX <= 32'd0;                       
        Ext_imm_2_EX <= 32'd0; 
        Ext_zero_2_EX <= 32'b0;                  
        Data_2_rs <= 32'd0; 
        Data_2_rt <= 32'd0; 
        JalAddr_2_EX <= 32'b0;              
        ALUop_2_EX <= 3'b011;  
    end
    else if(JALFlush_from_WB|PCScr_from_MEM)begin
        branch_beq_2_EX <= 1'b0; 
        branch_bne_2_EX <= 1'b0;     
        JALFlush_2_EX <= 1'b0;        // branch instruction

        ALUSrc_2_EX <= 1'b0;
        RegDst_2_EX <= 1'b0; 
        SignSelect_2_EX <= 1'b0;                    
        MemWrite_2_EX <= 1'b0; 
        MeMRead_2_EX <= 1'b0;            
        RegWrite_2_EX <= 1'b0; 
        MeMtoReg_2_EX <= 1'b0;
        pc4_2_EX <= 32'd0;                  
        inst_2_EX <= 32'd0;                       
        Ext_imm_2_EX <= 32'd0; 
        Ext_zero_2_EX <= 32'b0;                  
        Data_2_rs <= 32'd0; 
        Data_2_rt <= 32'd0; 
        JalAddr_2_EX <= 32'b0;              
        ALUop_2_EX <= 3'b011;  
    end
    else begin
        branch_beq_2_EX <= branch_beq_from_ID; 
        branch_bne_2_EX <= branch_bne_from_ID;     
        JALFlush_2_EX <= JALFlush_from_ID;
        ALUSrc_2_EX <= ALUSrc_from_ID;
        RegDst_2_EX <= RegDst_from_ID; 
        SignSelect_2_EX <= SignSelect_from_ID;                    
        MemWrite_2_EX <= MemWrite_from_ID; 
        MeMRead_2_EX <= MeMRead_from_ID;            
        RegWrite_2_EX <= RegWrite_from_ID; 
        MeMtoReg_2_EX <= MeMtoReg_from_ID;
        pc4_2_EX <= pc4_from_ID;                  
        inst_2_EX <= inst_from_ID;                       
        Ext_imm_2_EX <= Ext_imm_from_ID;  
        Ext_zero_2_EX <= Ext_zero_from_ID;                
        Data_2_rs <= Data_from_rs; 
        Data_2_rt <= Data_from_rt;  
        JalAddr_2_EX <= JalAddr_from_ID;              
        ALUop_2_EX <= ALUop_from_ID; 
    end
end
endmodule

module IFID(
    input clk, rst, IFIDFlush,       // IFIDFlush clear signals
    input IFIDWait,                  // IFIDWait keep signals
    input JRFlush_from_ID,
    input JFlush_from_ID,
    input JALFlush_from_WB,
    input PCScr,
    input [31:0] inst_from_IF,       // current instruction
    input [31:0] pc4_form_IF,        // next pc value
    output reg [31:0] pc4_to_ID, inst_to_ID
);

//wire IFIDWait_temp, JRFlush_temp, Jflush_temp, Jalflush_temp, Pcscr_temp;
//wire [31:0] inst_temp1, pc4_temp1,inst_temp2, pc4_temp2;

//assign inst_temp1 = (IFIDFlush|JRFlush_from_ID|JALFlush_from_WB|JFlush_from_ID|PCScr)?  32'b0:inst_from_IF;
//assign pc4_temp1 = (IFIDFlush|JRFlush_from_ID|JALFlush_from_WB|JFlush_from_ID|PCScr)?  32'b0:pc4_form_IF;

//assign inst_temp2 = (IFIDWait)?  pc4_to_ID:inst_temp1;
//assign pc4_temp2 = (IFIDWait)?  inst_to_ID:pc4_temp1;

always@(posedge clk or negedge rst)begin
    if(!rst)
    begin
        pc4_to_ID <= 32'b0;
        inst_to_ID <= 32'b0;
    end 
    else if(IFIDFlush|JRFlush_from_ID|JALFlush_from_WB|JFlush_from_ID|PCScr)begin
        pc4_to_ID <= 32'b0;
        inst_to_ID <= 32'b0;
    end
    else if(!IFIDWait) begin
         pc4_to_ID <= pc4_form_IF;
        inst_to_ID <= inst_from_IF;
    end
    else begin
        pc4_to_ID <= pc4_to_ID;
        inst_to_ID <= inst_to_ID;
    end
end
endmodule

module IdJumpAddr(
    input [25:0] instr_index_of_inst,
    input [31:0]  Pc4_from_IF_ID,
    output [31:0] JumpAddr_to_IF
);

assign JumpAddr_to_IF = {Pc4_from_IF_ID[31:28],instr_index_of_inst[25:0],2'b0};
endmodule

module MEMWB(
    input clk, rst,
    input JALFlush_from_WB,   // flush IDEX regiater

    // control signals    
    input JALFlush_from_MEM,                            // work at WB  
    input RegWrite_from_MEM, MeMtoReg_from_MEM,          // work at WB
    
    // data
    input [31:0] JalAddr_from_MEM,                 // work at WB    
    input [31:0] pc8_from_MEM,                     // work at WB    
    input [4:0]  rd_from_MEM,                      // work at WB
    input [31:0] Res_from_MEM,                     // work at WB
    input  overflow_from_MEM,                      // work at WB
    input [31:0] Data_from_dcache,                 // work at WB

    // out
    output reg JALFlush_2_WB,                            // work at WB  
    output reg RegWrite_2_WB, MeMtoReg_2_WB,          // work at WB
    
    // data
    output reg [31:0] JalAddr_2_WB,                 // work at WB    
    output reg [31:0] pc8_2_WB,                     // work at WB    
    output reg [4:0]  rd_2_WB,                      // work at WB
    output reg [31:0] Res_2_WB,                     // work at WB
    output reg  overflow_2_WB,                      // work at WB
    output reg [31:0] Data_2_WB                  // work at WB    
);
always@(posedge clk or negedge rst)begin
    if(!rst)begin
        JALFlush_2_WB <= 1'b0;                             // work at WB  
        RegWrite_2_WB <= 1'b0; 
        MeMtoReg_2_WB <= 1'b0;  
        JalAddr_2_WB <= 32'd0;                 // work at WB    
        pc8_2_WB <= 32'd0;                    // work at WB    
        rd_2_WB <= 5'd0;                      // work at WB
        Res_2_WB <= 32'd0;                     // work at WB
        overflow_2_WB <= 1'd0;                      // work at WB
        Data_2_WB  <= 32'd0;
    end else begin
        JALFlush_2_WB <= JALFlush_from_MEM;                             // work at WB  
        RegWrite_2_WB <= RegWrite_from_MEM; 
        MeMtoReg_2_WB <= MeMtoReg_from_MEM;  
        JalAddr_2_WB <= JalAddr_from_MEM;                 // work at WB    
        pc8_2_WB <= pc8_from_MEM;                    // work at WB    
        rd_2_WB <= rd_from_MEM;                      // work at WB
        Res_2_WB <= Res_from_MEM;                     // work at WB
        overflow_2_WB <= overflow_from_MEM;                      // work at WB
        Data_2_WB  <= Data_from_dcache;
    end
end

endmodule

module MIPSControl(
    input [31:0] inst_from_IF_ID,
    input clk, rst,
    input Detect_to_Control,               // clear signals when it is true
    
    output reg JRFlush, JFlush,            // Jump signals,work at ID
    output reg branch_beq, branch_bne,     // work at MEM
    output reg JALFlush,                   // work at WB

    output reg ALUSrc, RegDst,             // work at EX 
    output reg [2:0] ALUop,                // work at EX
    output reg MemWrite, MeMRead,          // work at MEM   
    output reg RegWrite, MeMtoReg,         // work at WB
    output reg SignSelect                  // work at EX
);
wire [5:0] Opcode;
wire [5:0] Funcode;
assign Opcode = inst_from_IF_ID[31:26];
assign Funcode = inst_from_IF_ID[5:0];

always@(*)begin
    if(Detect_to_Control==1)begin
        MemWrite <= 1'b0; 
        MeMRead <= 1'b0;
        RegWrite <= 1'b0; 
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0; 
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;      
    end else begin
    case(Opcode)
    6'b000000:begin      // R type
    // add,sub,and,or,xor,slt,sll,srl,nor,jr
        ALUop <= 3'b010;
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b1;       // address is rd
        ALUSrc <= 1'b0;       // read data2
        MemWrite <= 1'b0; 
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;
        MeMtoReg <= 1'b0;
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;
        SignSelect <= 1'b0;
        if(Funcode==6'b001000)JRFlush =1'b1;  // JR enable
        else JRFlush =1'b0; 
    end
    6'b100011:begin      // lw
        ALUop <= 3'b000;
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read offset
        MemWrite <= 1'b0; 
        MeMRead <= 1'b1;      // load data
        RegWrite <= 1'b1;
        MeMtoReg <= 1'b1;     // data from dcache
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b101011:begin      // sw
        ALUop <= 3'b000;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read offset
        MemWrite <= 1'b1;     // save data
        MeMRead <= 1'b0;
        RegWrite <= 1'b0;     // no need to write regs when sw
        MeMtoReg <= 1'b1;     // data from dcache    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b001000:begin     // addi
        ALUop <= 3'b111;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b001001:begin     //addiu
        ALUop <= 3'b000;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b001100:begin     // andi
        ALUop <= 3'b100;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b0;
    end
    6'b001101:begin      // ori
        ALUop <= 3'b011;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b0;
    end
    6'b001110:begin     // xori
        ALUop <= 3'b101;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b0;
    end
    6'b001111:begin     // lui
        ALUop <= 3'b110;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b0;
    end
    6'b000100:begin      //beq
        ALUop <= 3'b001;        
        branch_beq <= 1'b1; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is immediate
        ALUSrc <= 1'b0;       // read rt
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b0;     // no need to write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b000101:begin      // bne
        ALUop <= 3'b001;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b1;        
        RegDst <= 1'b0;       // address is immediate
        ALUSrc <= 1'b0;       // read rt
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b0;     // no need to write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b000010:begin     // J
        ALUop <= 3'b001;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is immediate
        ALUSrc <= 1'b0;       // read rt
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b0;     // no need to write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b1;       // J enable
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b000011:begin     // Jal
        ALUop <= 3'b001;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       
        ALUSrc <= 1'b0;       
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // need to write regs 
        MeMtoReg <= 1'b0;      
        JALFlush <= 1'b1;     // Jal enable
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    default:begin
        ALUop <= 3'b001;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       
        ALUSrc <= 1'b0;       
        MemWrite <= 1'b0;     // can't write cache
        MeMRead <= 1'b0;      // can't read cache
        RegWrite <= 1'b0;     // can't write regs 
        MeMtoReg <= 1'b0;      
        JALFlush <= 1'b0;    
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    endcase
    end
end
endmodule

module Mux32_2(
    input [31:0] in1, in2,
    input clt,
    output wire [31:0] out
);
assign out = (clt)? in1:in2;
endmodule 

module Mux5_2(
    input [4:0] in1, in2,
    input clt,
    output wire [4:0] out
);
assign out = (clt)? in1:in2;
endmodule

module PCreg(
    input clk, rst,
    input PCwait,       //keep the PC value when pipeline stall
    input [31:0] PCin,
    output reg [31:0] PCout,
    output wire [31:0] PCout4
);
always@(posedge clk or negedge rst)begin
    if(!rst) PCout <= 32'b0;
    else if(PCwait==1) PCout <= PCout;
    else PCout <= PCin;
end

assign PCout4 = PCout + 32'd4;

endmodule

module PCscr(
    input bne_EX_MEM, beq_EX_MEM,
    input zero_EX_MEM,
    output Pcscr
);

assign Pcscr = (bne_EX_MEM &(~zero_EX_MEM))|(beq_EX_MEM & zero_EX_MEM);

endmodule

module Regs(
    input clk, rst, RegWrite,
    input [4:0] ReadAddr_rs, ReadAddr_rt,
    input [4:0] WriteAddr_rd,              //需要注意的是不同指令可能名称不同
    input [31:0] WriteData,
    output [31:0] ReadData_rs, ReadData_rt 
);
reg [31:0] RegRam[31:0];
integer  i;

always@(negedge clk or negedge rst)
begin
  if(!rst) begin
      for(i=0; i<32; i=i+1)begin
      RegRam[i] <= 0;
      end
  end else if(RegWrite==1)begin
      RegRam[WriteAddr_rd] <= WriteData;
  end 
end

assign ReadData_rs = ((RegWrite==1)&(WriteAddr_rd==ReadAddr_rs))? WriteData:RegRam[ReadAddr_rs];
assign ReadData_rt = ((RegWrite==1)&(WriteAddr_rd==ReadAddr_rt))? WriteData:RegRam[ReadAddr_rt];
    
endmodule

module SignExtend(
    input [15:0] imme_of_inst,
    output [31:0] SignImme, ZeroExtend
);
assign SignImme = {{16{imme_of_inst[15]}},imme_of_inst[15:0]};
assign ZeroExtend = {16'b0,imme_of_inst[15:0]};
endmodule

module WB(
    // control signals    
    input JALFlush_from_MEM_WB,                            // work at WB  
    input RegWrite_from_MEM_WB, MeMtoReg_from_MEM_WB,          // work at WB
    
    // data
    input [31:0] JalAddr_from_MEM_WB,                 // work at WB    
    input [31:0] pc8_from_MEM_WB,                     // work at WB    
    input [4:0]  rd_from_MEM_WB,                      // work at WB
    input [31:0] Res_from_MEM_WB,                     // work at WB
    input  overflow_from_MEM_WB,                      // work at WB
    input [31:0] Data_from_MEM_WB,                 // work at WB

    output Regwrite_2_regs,
    output JALFlush_2_IF,
    output [31:0] JalAddr_2_IF,
    output [31:0] wb_data,
    output [4:0] wb_addr
);

wire [31:0] wb2_data;
assign wb2_data = (MeMtoReg_from_MEM_WB)? Data_from_MEM_WB:Res_from_MEM_WB;
// if memtoreg is ture, dcache give data, else alu
assign Regwrite_2_regs = RegWrite_from_MEM_WB & (~overflow_from_MEM_WB);

assign wb_data = (JALFlush_from_MEM_WB)? pc8_from_MEM_WB:wb2_data;
assign wb_addr = (JALFlush_from_MEM_WB)? 5'd31:rd_from_MEM_WB;

assign JALFlush_2_IF =JALFlush_from_MEM_WB;
assign JalAddr_2_IF =JalAddr_from_MEM_WB;
endmodule

module dcache(clk,reset,we,re,addr,wdata,rdata);
  input   clk, we,re;
  input reset;
  input[31:0]   addr, wdata;
  output[31:0]  rdata; 
  
  reg[31:0]   RAM[383:0]; 
 
  //assign rdata = re ? RAM[addr[31:0]]:0;
 
  assign rdata = re ? RAM[addr[8:0]]:0;
 
 
	always@(posedge clk or negedge reset)
	 begin
		if (~reset)
		begin
        RAM[0] <= 32'h00000063;
        RAM[1] <= 32'h0000007c;
        RAM[2] <= 32'h00000077;
        RAM[3] <= 32'h0000007b;
        RAM[4] <= 32'h000000f2;
        RAM[5] <= 32'h0000006b;
        RAM[6] <= 32'h0000006f;
        RAM[7] <= 32'h000000c5;
        RAM[8] <= 32'h00000030;
        RAM[9] <= 32'h00000001;
        RAM[10] <= 32'h00000067;
        RAM[11] <= 32'h0000002b;
        RAM[12] <= 32'h000000fe;
        RAM[13] <= 32'h000000d7;
        RAM[14] <= 32'h000000ab;
        RAM[15] <= 32'h00000076;
        RAM[16] <= 32'h000000ca;
        RAM[17] <= 32'h00000082;
        RAM[18] <= 32'h000000c9;
        RAM[19] <= 32'h0000007d;
        RAM[20] <= 32'h000000fa;
        RAM[21] <= 32'h00000059;
        RAM[22] <= 32'h00000047;
        RAM[23] <= 32'h000000f0;
        RAM[24] <= 32'h000000ad;
        RAM[25] <= 32'h000000d4;
        RAM[26] <= 32'h000000a2;
        RAM[27] <= 32'h000000af;
        RAM[28] <= 32'h0000009c;
        RAM[29] <= 32'h000000a4;
        RAM[30] <= 32'h00000072;
        RAM[31] <= 32'h000000c0;
        RAM[32] <= 32'h000000b7;
        RAM[33] <= 32'h000000fd;
        RAM[34] <= 32'h00000093;
        RAM[35] <= 32'h00000026;
        RAM[36] <= 32'h00000036;
        RAM[37] <= 32'h0000003f;
        RAM[38] <= 32'h000000f7;
        RAM[39] <= 32'h000000cc;
        RAM[40] <= 32'h00000034;
        RAM[41] <= 32'h000000a5;
        RAM[42] <= 32'h000000e5;
        RAM[43] <= 32'h000000f1;
        RAM[44] <= 32'h00000071;
        RAM[45] <= 32'h000000d8;
        RAM[46] <= 32'h00000031;
        RAM[47] <= 32'h00000015;
        RAM[48] <= 32'h00000004;
        RAM[49] <= 32'h000000c7;
        RAM[50] <= 32'h00000023;
        RAM[51] <= 32'h000000c3;
        RAM[52] <= 32'h00000018;
        RAM[53] <= 32'h00000096;
        RAM[54] <= 32'h00000005;
        RAM[55] <= 32'h0000009a;
        RAM[56] <= 32'h00000007;
        RAM[57] <= 32'h00000012;
        RAM[58] <= 32'h00000080;
        RAM[59] <= 32'h000000e2;
        RAM[60] <= 32'h000000eb;
        RAM[61] <= 32'h00000027;
        RAM[62] <= 32'h000000b2;
        RAM[63] <= 32'h00000075;
        RAM[64] <= 32'h00000009;
        RAM[65] <= 32'h00000083;
        RAM[66] <= 32'h0000002c;
        RAM[67] <= 32'h0000001a;
        RAM[68] <= 32'h0000001b;
        RAM[69] <= 32'h0000006e;
        RAM[70] <= 32'h0000005a;
        RAM[71] <= 32'h000000a0;
        RAM[72] <= 32'h00000052;
        RAM[73] <= 32'h0000003b;
        RAM[74] <= 32'h000000d6;
        RAM[75] <= 32'h000000b3;
        RAM[76] <= 32'h00000029;
        RAM[77] <= 32'h000000e3;
        RAM[78] <= 32'h0000002f;
        RAM[79] <= 32'h00000084;
        RAM[80] <= 32'h00000053;
        RAM[81] <= 32'h000000d1;
        RAM[82] <= 32'h00000000;
        RAM[83] <= 32'h000000ed;
        RAM[84] <= 32'h00000020;
        RAM[85] <= 32'h000000fc;
        RAM[86] <= 32'h000000b1;
        RAM[87] <= 32'h0000005b;
        RAM[88] <= 32'h0000006a;
        RAM[89] <= 32'h000000cb;
        RAM[90] <= 32'h000000be;
        RAM[91] <= 32'h00000039;
        RAM[92] <= 32'h0000004a;
        RAM[93] <= 32'h0000004c;
        RAM[94] <= 32'h00000058;
        RAM[95] <= 32'h000000cf;
        RAM[96] <= 32'h000000d0;
        RAM[97] <= 32'h000000ef;
        RAM[98] <= 32'h000000aa;
        RAM[99] <= 32'h000000fb;
        RAM[100] <= 32'h00000043;
        RAM[101] <= 32'h0000004d;
        RAM[102] <= 32'h00000033;
        RAM[103] <= 32'h00000085;
        RAM[104] <= 32'h00000045;
        RAM[105] <= 32'h000000f9;
        RAM[106] <= 32'h00000002;
        RAM[107] <= 32'h0000007f;
        RAM[108] <= 32'h00000050;
        RAM[109] <= 32'h0000003c;
        RAM[110] <= 32'h0000009f;
        RAM[111] <= 32'h000000a8;
        RAM[112] <= 32'h00000051;
        RAM[113] <= 32'h000000a3;
        RAM[114] <= 32'h00000040;
        RAM[115] <= 32'h0000008f;
        RAM[116] <= 32'h00000092;
        RAM[117] <= 32'h0000009d;
        RAM[118] <= 32'h00000038;
        RAM[119] <= 32'h000000f5;
        RAM[120] <= 32'h000000bc;
        RAM[121] <= 32'h000000b6;
        RAM[122] <= 32'h000000da;
        RAM[123] <= 32'h00000021;
        RAM[124] <= 32'h00000010;
        RAM[125] <= 32'h000000ff;
        RAM[126] <= 32'h000000f3;
        RAM[127] <= 32'h000000d2;
        RAM[128] <= 32'h000000cd;
        RAM[129] <= 32'h0000000c;
        RAM[130] <= 32'h00000013;
        RAM[131] <= 32'h000000ec;
        RAM[132] <= 32'h0000005f;
        RAM[133] <= 32'h00000097;
        RAM[134] <= 32'h00000044;
        RAM[135] <= 32'h00000017;
        RAM[136] <= 32'h000000c4;
        RAM[137] <= 32'h000000a7;
        RAM[138] <= 32'h0000007e;
        RAM[139] <= 32'h0000003d;
        RAM[140] <= 32'h00000064;
        RAM[141] <= 32'h0000005d;
        RAM[142] <= 32'h00000019;
        RAM[143] <= 32'h00000073;
        RAM[144] <= 32'h00000060;
        RAM[145] <= 32'h00000081;
        RAM[146] <= 32'h0000004f;
        RAM[147] <= 32'h000000dc;
        RAM[148] <= 32'h00000022;
        RAM[149] <= 32'h0000002a;
        RAM[150] <= 32'h00000090;
        RAM[151] <= 32'h00000088;
        RAM[152] <= 32'h00000046;
        RAM[153] <= 32'h000000ee;
        RAM[154] <= 32'h000000b8;
        RAM[155] <= 32'h00000014;
        RAM[156] <= 32'h000000de;
        RAM[157] <= 32'h0000005e;
        RAM[158] <= 32'h0000000b;
        RAM[159] <= 32'h000000db;
        RAM[160] <= 32'h000000e0;
        RAM[161] <= 32'h00000032;
        RAM[162] <= 32'h0000003a;
        RAM[163] <= 32'h0000000a;
        RAM[164] <= 32'h00000049;
        RAM[165] <= 32'h00000006;
        RAM[166] <= 32'h00000024;
        RAM[167] <= 32'h0000005c;
        RAM[168] <= 32'h000000c2;
        RAM[169] <= 32'h000000d3;
        RAM[170] <= 32'h000000ac;
        RAM[171] <= 32'h00000062;
        RAM[172] <= 32'h00000091;
        RAM[173] <= 32'h00000095;
        RAM[174] <= 32'h000000e4;
        RAM[175] <= 32'h00000079;
        RAM[176] <= 32'h000000e7;
        RAM[177] <= 32'h000000c8;
        RAM[178] <= 32'h00000037;
        RAM[179] <= 32'h0000006d;
        RAM[180] <= 32'h0000008d;
        RAM[181] <= 32'h000000d5;
        RAM[182] <= 32'h0000004e;
        RAM[183] <= 32'h000000a9;
        RAM[184] <= 32'h0000006c;
        RAM[185] <= 32'h00000056;
        RAM[186] <= 32'h000000f4;
        RAM[187] <= 32'h000000ea;
        RAM[188] <= 32'h00000065;
        RAM[189] <= 32'h0000007a;
        RAM[190] <= 32'h000000ae;
        RAM[191] <= 32'h00000008;
        RAM[192] <= 32'h000000ba;
        RAM[193] <= 32'h00000078;
        RAM[194] <= 32'h00000025;
        RAM[195] <= 32'h0000002e;
        RAM[196] <= 32'h0000001c;
        RAM[197] <= 32'h000000a6;
        RAM[198] <= 32'h000000b4;
        RAM[199] <= 32'h000000c6;
        RAM[200] <= 32'h000000e8;
        RAM[201] <= 32'h000000dd;
        RAM[202] <= 32'h00000074;
        RAM[203] <= 32'h0000001f;
        RAM[204] <= 32'h0000004b;
        RAM[205] <= 32'h000000bd;
        RAM[206] <= 32'h0000008b;
        RAM[207] <= 32'h0000008a;
        RAM[208] <= 32'h00000070;
        RAM[209] <= 32'h0000003e;
        RAM[210] <= 32'h000000b5;
        RAM[211] <= 32'h00000066;
        RAM[212] <= 32'h00000048;
        RAM[213] <= 32'h00000003;
        RAM[214] <= 32'h000000f6;
        RAM[215] <= 32'h0000000e;
        RAM[216] <= 32'h00000061;
        RAM[217] <= 32'h00000035;
        RAM[218] <= 32'h00000057;
        RAM[219] <= 32'h000000b9;
        RAM[220] <= 32'h00000086;
        RAM[221] <= 32'h000000c1;
        RAM[222] <= 32'h0000001d;
        RAM[223] <= 32'h0000009e;
        RAM[224] <= 32'h000000e1;
        RAM[225] <= 32'h000000f8;
        RAM[226] <= 32'h00000098;
        RAM[227] <= 32'h00000011;
        RAM[228] <= 32'h00000069;
        RAM[229] <= 32'h000000d9;
        RAM[230] <= 32'h0000008e;
        RAM[231] <= 32'h00000094;
        RAM[232] <= 32'h0000009b;
        RAM[233] <= 32'h0000001e;
        RAM[234] <= 32'h00000087;
        RAM[235] <= 32'h000000e9;
        RAM[236] <= 32'h000000ce;
        RAM[237] <= 32'h00000055;
        RAM[238] <= 32'h00000028;
        RAM[239] <= 32'h000000df;
        RAM[240] <= 32'h0000008c;
        RAM[241] <= 32'h000000a1;
        RAM[242] <= 32'h00000089;
        RAM[243] <= 32'h0000000d;
        RAM[244] <= 32'h000000bf;
        RAM[245] <= 32'h000000e6;
        RAM[246] <= 32'h00000042;
        RAM[247] <= 32'h00000068;
        RAM[248] <= 32'h00000041;
        RAM[249] <= 32'h00000099;
        RAM[250] <= 32'h0000002d;
        RAM[251] <= 32'h0000000f;
        RAM[252] <= 32'h000000b0;
        RAM[253] <= 32'h00000054;
        RAM[254] <= 32'h000000bb;
        RAM[255] <= 32'h00000016;
        RAM[256] <= 32'h00000000;
        RAM[257] <= 32'h00000000;
        RAM[258] <= 32'h00000000;
        RAM[259] <= 32'h00000000;
        RAM[260] <= 32'h3243f6a8;         // plaintext
        RAM[261] <= 32'h885a308d;
        RAM[262] <= 32'h313198a2;
        RAM[263] <= 32'he0370734;
        RAM[264] <= 32'h00000000;
        RAM[265] <= 32'h00000000;
        RAM[266] <= 32'h00000000;
        RAM[267] <= 32'h00000000;
        RAM[268] <= 32'h00000000;
        RAM[269] <= 32'h00000000;
        RAM[270] <= 32'h2b7e1516;        // key
        RAM[271] <= 32'h28aed2a6;
        RAM[272] <= 32'habf71588;
        RAM[273] <= 32'h09cf4f3c;
        RAM[274] <= 32'h00000000;
        RAM[275] <= 32'h00000000;
        RAM[276] <= 32'h00000000;
        RAM[277] <= 32'h00000000;
        RAM[278] <= 32'h00000000;
        RAM[279] <= 32'h00000000;
        RAM[280] <= 32'h00000000;
        RAM[281] <= 32'h00000000;
        RAM[282] <= 32'h00000000;
        RAM[283] <= 32'h00000000;
        RAM[284] <= 32'h00000000;
        RAM[285] <= 32'h00000000;
        RAM[286] <= 32'h00000000;
        RAM[287] <= 32'h00000000;
        RAM[288] <= 32'h00000000;
        RAM[289] <= 32'h00000000;
        RAM[290] <= 32'h00000000;
        RAM[291] <= 32'h00000000;
        RAM[292] <= 32'h00000000;
        RAM[293] <= 32'h00000000;
        RAM[294] <= 32'h00000000;
        RAM[295] <= 32'h00000000;
        RAM[296] <= 32'h00000000;
        RAM[297] <= 32'h00000000;
        RAM[298] <= 32'h00000000;
        RAM[299] <= 32'h00000000;
        RAM[300] <= 32'h00000000;
        RAM[301] <= 32'h00000000;
        RAM[302] <= 32'h00000000;
        RAM[303] <= 32'h00000000;
        RAM[304] <= 32'h00000000;
        RAM[305] <= 32'h00000000;
        RAM[306] <= 32'h00000000;
        RAM[307] <= 32'h00000000;
        RAM[308] <= 32'h00000000;
        RAM[309] <= 32'h00000000;
        RAM[310] <= 32'h00000000;
        RAM[311] <= 32'h00000000;
        RAM[312] <= 32'h00000000;
        RAM[313] <= 32'h00000000;
        RAM[314] <= 32'h00000000;
        RAM[315] <= 32'h00000000;
        RAM[316] <= 32'h00000000;
        RAM[317] <= 32'h00000000;
        RAM[318] <= 32'h00000000;
        RAM[319] <= 32'h00000000;
        RAM[320] <= 32'h01000000;          // RC
        RAM[321] <= 32'h02000000;
        RAM[322] <= 32'h04000000;
        RAM[323] <= 32'h08000000;
        RAM[324] <= 32'h10000000;
        RAM[325] <= 32'h20000000;
        RAM[326] <= 32'h40000000;
        RAM[327] <= 32'h80000000;
        RAM[328] <= 32'h1b000000;
        RAM[329] <= 32'h36000000;
        RAM[330] <= 32'h00000000;
        RAM[331] <= 32'h00000000;
        RAM[332] <= 32'h00000000;
        RAM[333] <= 32'h00000000;
        RAM[334] <= 32'h00000000;
        RAM[335] <= 32'h00000000;
        RAM[336] <= 32'h00000000;
        RAM[337] <= 32'h00000000;
        RAM[338] <= 32'h00000000;
        RAM[339] <= 32'h00000000;
        RAM[340] <= 32'h00000000;
        RAM[341] <= 32'h00000000;
        RAM[342] <= 32'h00000000;
        RAM[343] <= 32'h00000000;
        RAM[344] <= 32'h00000000;
        RAM[345] <= 32'h00000000;
        RAM[346] <= 32'h00000000;
        RAM[347] <= 32'h00000000;
        RAM[348] <= 32'h00000000;
        RAM[349] <= 32'h00000000;
        RAM[350] <= 32'h00000000;
        RAM[351] <= 32'h00000000;
        RAM[352] <= 32'h00000000;
        RAM[353] <= 32'h00000000;
        RAM[354] <= 32'h00000000;
        RAM[355] <= 32'h00000000;
        RAM[356] <= 32'h00000000;
        RAM[357] <= 32'h00000000;
        RAM[358] <= 32'h00000000;
        RAM[359] <= 32'h00000000;
        RAM[360] <= 32'h00000000;
        RAM[361] <= 32'h00000000;
        RAM[362] <= 32'h00000000;
        RAM[363] <= 32'h00000000;
        RAM[364] <= 32'h00000000;
        RAM[365] <= 32'h00000000;
        RAM[366] <= 32'h00000000;
        RAM[367] <= 32'h00000000;
        RAM[368] <= 32'h00000000;
        RAM[369] <= 32'h00000000;
        RAM[370] <= 32'h00000000;
        RAM[371] <= 32'h00000000;
        RAM[372] <= 32'h00000000;
        RAM[373] <= 32'h00000000;
        RAM[374] <= 32'h00000000;
        RAM[375] <= 32'h00000000;
        RAM[376] <= 32'h00000000;
        RAM[377] <= 32'h00000000;
        RAM[378] <= 32'h00000000;
        RAM[379] <= 32'h00000000;
        RAM[380] <= 32'h00000000;
        RAM[381] <= 32'h00000000;
        RAM[382] <= 32'h00000000;
        RAM[383] <= 32'h00000000;
		end
		else begin
			if(we)
				//RAM[addr[31:0]]<= wdata;  
				RAM[addr[8:0]]<= wdata; 
		end
	 end

	
endmodule

module icache(
	input rst,
	input [31:0] pc,
	output [31:0] inst
);

reg [31:0] _ROM [1023:0];
integer  i;

assign inst=_ROM[pc[11:2]];
//initial begin
//		$readmemh("/data2/class/lsg/lsg15/MIPS/mips.txt",_ROM);
//	end
always@(negedge rst) begin
// R type test
	_ROM[0] = 32'h3401_0110;
	_ROM[1] = 32'h3803_0010;
	_ROM[2] = 32'h0023_2024;
	_ROM[3] = 32'h0023_2824;
	_ROM[4] = 32'h0023_3024;
	_ROM[5] = 32'h0023_3824;
	_ROM[6] = 32'h3c01_0000;
	_ROM[7] = 32'h3421_ffff;
	_ROM[8] = 32'h0021_1020;
	_ROM[9] = 32'h2028_0e00;
	_ROM[10] = 32'h3c01_0000;
	_ROM[11] = 32'h3421_ffff;
	_ROM[12] = 32'h0021_4821;
	_ROM[13] = 32'h302a_1234;
	_ROM[14] = 32'h3c0b_abcd;
	_ROM[15] = 32'h0085_6025;
	_ROM[16] = 32'h0003_6826;
	_ROM[17] = 32'h0085_7027;
	_ROM[18] = 32'h000e_7900;
	_ROM[19] = 32'h000e_8102;
	_ROM[20] = 32'h3401_abcd;
	_ROM[21] = 32'h3803_a123;
	_ROM[22] = 32'h0061_2024;
	_ROM[23] = 32'h0061_2824;
	_ROM[24] = 32'h0061_3024;
	_ROM[25] = 32'h0061_3824;

//  sw and lw test
/*
    _ROM[0] = 32'h2001_3fff;
	_ROM[1] = 32'h3402_0020;
	_ROM[2] = 32'hac01_0004;
	_ROM[3] = 32'h0020_1025;
	_ROM[4] = 32'h8c45_0064;
	_ROM[5] = 32'h00a1_3020;
	*/
	//branch test, beq,bne,j,jal,jr,and slt
	/*
	_ROM[0] = 32'h3407_abcd;
	_ROM[1] = 32'h2001_0000;
	_ROM[2] = 32'h2002_0008;
	_ROM[3] = 32'h2003_0000;
	_ROM[4] = 32'h2021_0001;
	_ROM[5] = 32'h0c00_000c;
	_ROM[6] = 32'h20a5_0001;
	_ROM[7] = 32'h1041_0001;
	_ROM[8] = 32'h0800_0004;
	_ROM[9] = 32'h0023_302a;
	_ROM[10] = 32'h14c3_fff5;
	_ROM[11] = 32'h3807_1234;
	_ROM[12] = 32'h0023_1820;
	_ROM[13] = 32'h03e0_0008;
	*/
	// KeyExtent
	/*
	_ROM[0] = 32'h3415010e;
	_ROM[1] = 32'h22b6002b;
	_ROM[2] = 32'h8ea10000;
	_ROM[3] = 32'h22b50001;
	_ROM[4] = 32'h8ea20000;
	_ROM[5] = 32'h22b50001;
	_ROM[6] = 32'h8ea30000;
	_ROM[7] = 32'h22b50001;
	_ROM[8] = 32'h8ea40000;
	_ROM[9] = 32'h34140140;
	_ROM[10] = 32'h0c00001a;
	_ROM[11] = 32'h00000000;
	_ROM[12] = 32'h22b40001;
	_ROM[13] = 32'h00250826;
	_ROM[14] = 32'h00461026;
	_ROM[15] = 32'h00671826;
	_ROM[16] = 32'h00882026;
	_ROM[17] = 32'h22b50001;
	_ROM[18] = 32'haea10000;
	_ROM[19] = 32'h22b50001;
	_ROM[20] = 32'haea20000;
	_ROM[21] = 32'h22b50001;
	_ROM[22] = 32'haea30000;
	_ROM[23] = 32'h22b50001;
	_ROM[24] = 32'haea40000;
	_ROM[25] = 32'h16b6fff0;
	_ROM[26] = 32'h00042e02;
	_ROM[27] = 32'h30a500ff;
	_ROM[28] = 32'h8ca60000;
	_ROM[29] = 32'h00042c02;
	_ROM[30] = 32'h30a500ff;
	_ROM[31] = 32'h8ca70000;
	_ROM[32] = 32'h00042a02;
	_ROM[33] = 32'h30a500ff;
	_ROM[34] = 32'h8ca80000;
	_ROM[35] = 32'h308500ff;
	_ROM[36] = 32'h8ca90000;
	_ROM[37] = 32'h00075600;
	_ROM[38] = 32'h00085c00;
	_ROM[39] = 32'h00086200;
	_ROM[40] = 32'h00ca6825;
	_ROM[41] = 32'h016c7025;
	_ROM[42] = 32'h01ae7825;
	_ROM[43] = 32'h8e900000;
	_ROM[44] = 32'h01f02826;
	_ROM[45] = 32'h03e00008;
	*/
	/*
	initial begin
		$readmemh("E:/Microprocessor/Project/MARS/key_extent.txt",_ROM);
	end
	*/
	/*
	for(i=46;i<1024;i=i+1)begin
		_ROM[i] <= 32'b0;
	end
	*/
end  
endmodule


=======
module MIPS_top(
    input clk, rst,
    output [31:0] out 
);

// IF output signals wire
wire [31:0] Pcout4_f_IF;
wire [31:0] inst_f_IF;

// register IF/ID signals
wire [31:0] pc4_f_IFID, inst_f_IFID;

//**************
// ID output 
// hazard module
wire IFIDWait_f_hd;
wire PCwait_f_hd;
wire Detect_to_Control_f_hd;

// control signals
wire JRFlush_f_id, JFlush_f_id;            // Jump signals,work at ID
wire branch_beq_f_id, branch_bne_f_id;     // work at MEM
wire JALFlush_f_id;                   // work at WB
wire ALUSrc_f_id, RegDst_f_id;             // work at EX 
wire [2:0] ALUop_f_id;                // work at EX
wire SignSelect_f_id;
wire MemWrite_f_id, MeMRead_f_id;          // work at MEM   
wire RegWrite_f_id, MeMtoReg_f_id; 

// from regs
wire [31:0] ReadData_rs_f_reg, ReadData_rt_f_reg;

// Addr of J instruction
wire [31:0] JumpAddr_f_JAddr;

// extent of immediate 
wire [31:0] SignImme_f_Sign;
wire [31:0] ZeroExtend_f_sign;

// signals from ID/EX
wire beq_f_id_ex, bne_f_id_ex;     // work at MEM
wire JALFlush_f_id_ex;                        // work at WB
wire ALUSrc_f_id_ex, RegDst_f_id_ex;               // work at EX 
wire SignSelect_f_id_ex;
wire [2:0] ALUop_f_id_ex;                       // work at EX
wire MemWrite_f_id_ex, MeMRead_f_id_ex;            // work at MEM   
wire RegWrite_f_id_ex, MeMtoReg_f_id_ex;           // work at WB
wire [31:0] pc4_f_id_ex;                        // pc+4
wire [31:0] inst_f_id_ex;                       // instruction
wire [31:0] Ext_imm_f_id_ex;                    //sign extend value
wire [31:0] Ext_zero_f_id_ex;
wire [31:0] Data_rs_f_id_ex, Data_rt_f_id_ex;             // data from regs 
wire [31:0] JalAddr_f_id_ex;

//**********************
// EX part
wire [31:0] pc8_f_ex;
wire [31:0] AddrBranch_f_ex;

// alu 
wire [31:0] alu1, alu2_1, alu2_2 ,alu2_sign_mux;
wire [1:0] ForwardA_f_forward, ForwardB_f_forward;

wire [31:0] rd_f_alu;  //more generally, it is just ALUout
wire Zero_f_alu; 
wire overflow_f_alu;
wire [4:0] rd_f_mux;

// ex/mem
wire beq_f_ex_mem, bne_f_ex_mem;                  // work at MEM
wire JALFlush_f_ex_mem;                          // work at WB
wire MemWrite_f_ex_mem, MeMRead_f_ex_mem;           // work at MEM   
wire RegWrite_f_ex_mem, MeMtoReg_f_ex_mem;          // work at WB
wire [31:0] JalAddr_f_ex_mem;                 // work at WB    
wire [31:0] pc8_f_ex_mem;                     // work at WB    
wire [4:0]  rd_f_ex_mem;                      // work at WB
wire  overflow_f_ex_mem;                      // work at WB
wire  zero_f_ex_mem;                          // work at MEM
wire [31:0] BranchAddr_f_ex_mem;              // address of bne,beq,work at MEM
wire [31:0] Res_f_ex_mem;                     // work at MEM
wire [31:0] Data_rt_f_ex_mem;

//****************
// mem

wire Pcscr_f_mem;
wire [31:0] rdata_f_dcache;

// mem_wb
wire JALFlush_f_mem_wb;                            // work at WB  
wire RegWrite_f_mem_wb, MeMtoReg_f_mem_wb;          // work at WB
wire [31:0] JalAddr_f_mem_wb;                 // work at WB    
wire [31:0] pc8_f_mem_wb;                     // work at WB    
wire [4:0]  rd_f_mem_wb;                      // work at WB
wire [31:0] Res_f_mem_wb;                     // work at WB
wire  overflow_f_mem_wb;                      // work at WB
wire [31:0] Data_f_mem_wb;

//***************
// wb
wire Regwrite_f_wb;
wire JALFlush_f_wb;
wire [31:0] JalAddr_f_wb;
wire [31:0] wb_data_f_wb;
wire [4:0] wb_addr_f_wb;

assign out = Res_f_ex_mem;

IF uut_if(
    .clk(clk), .rst(rst),
    .jr_from_id(JRFlush_f_id), 
    .j_from_id(JFlush_f_id), 
    .Pcscr_from_mem(Pcscr_f_mem), 
    .jal_from_wb(JALFlush_f_wb),
    .JrAddr_f_id(ReadData_rs_f_reg), 
    .JAddr_f_id(JumpAddr_f_JAddr), 
    .JalAddr_f_wb(JalAddr_f_wb), 
    .PscrAddr_f_mem(BranchAddr_f_ex_mem),
    .PCwait(PCwait_f_hd),
    .inst(inst_f_IF),
    .PCout4(Pcout4_f_IF)    
);

IFID uut_ifid(
    .clk(clk), .rst(rst), 
    .IFIDFlush(1'b0),                           // IFIDFlush clear signals
    .IFIDWait(IFIDWait_f_hd),                   // IFIDWait keep signals
    .JRFlush_from_ID(JRFlush_f_id),
    .JFlush_from_ID(JFlush_f_id),
    .JALFlush_from_WB(JALFlush_f_wb),
    .PCScr(Pcscr_f_mem),
    .inst_from_IF(inst_f_IF),                           // current instruction
    .pc4_form_IF(Pcout4_f_IF),                             // next pc value
    .pc4_to_ID(pc4_f_IFID), 
    .inst_to_ID(inst_f_IFID)
);
HazardDetext uut_hd(
    .MeMRead_from_ID_EX(MeMRead_f_id_ex),
    .rt_from_ID_EX(inst_f_id_ex[20:16]),
    .rs_from_IF_ID(inst_f_IFID[25:21]), 
    .rt_from_IF_ID(inst_f_IFID[20:16]),
    .IFIDWait(IFIDWait_f_hd), 
    .PCwait(PCwait_f_hd), 
    .Detect_to_Control(Detect_to_Control_f_hd)
);
MIPSControl uut_control(
    .inst_from_IF_ID(inst_f_IFID),
    .clk(clk), .rst(rst),
    .Detect_to_Control(Detect_to_Control_f_hd),               // clear signals when it is true
    
    .JRFlush(JRFlush_f_id), 
    .JFlush(JFlush_f_id),            // Jump signals,work at ID
    .branch_beq(branch_beq_f_id), 
    .branch_bne(branch_bne_f_id),     // work at MEM
    .JALFlush(JALFlush_f_id),                   // work at WB

    .ALUSrc(ALUSrc_f_id), 
    .RegDst(RegDst_f_id),             // work at EX 
    .ALUop(ALUop_f_id),                // work at EX
    .MemWrite(MemWrite_f_id), 
    .MeMRead(MeMRead_f_id),          // work at MEM   
    .RegWrite(RegWrite_f_id), 
    .MeMtoReg(MeMtoReg_f_id),          // work at WB
    .SignSelect(SignSelect_f_id)
);
Regs uut_regs(
    .clk(clk), .rst(rst), 
    .RegWrite(Regwrite_f_wb),
    .ReadAddr_rs(inst_f_IFID[25:21]), 
    .ReadAddr_rt(inst_f_IFID[20:16]),
    .WriteAddr_rd(wb_addr_f_wb),              //需要注意的是不同指令可能名称不同
    .WriteData(wb_data_f_wb),
    .ReadData_rs(ReadData_rs_f_reg), 
    .ReadData_rt(ReadData_rt_f_reg) 
);
IdJumpAddr uut_idjumpAddr(
    .instr_index_of_inst(inst_f_IFID[25:0]),
    .Pc4_from_IF_ID(pc4_f_IFID),
    .JumpAddr_to_IF(JumpAddr_f_JAddr)
);
SignExtend uut_sign(
    .imme_of_inst(inst_f_IFID[15:0]),
    .SignImme(SignImme_f_Sign),
    .ZeroExtend(ZeroExtend_f_sign)
);
IDEX uut_idex(
    .clk(clk), .rst(rst), 
    .JALFlush_from_WB(JALFlush_f_wb),   // flush IDEX regiater
    .PCScr_from_MEM(Pcscr_f_mem),

    // control signals
    .branch_beq_from_ID(branch_beq_f_id), 
    .branch_bne_from_ID(branch_bne_f_id),      // work at MEM
    .JALFlush_from_ID(JALFlush_f_id),                            // work at WB

    .ALUSrc_from_ID(ALUSrc_f_id), 
    .RegDst_from_ID(RegDst_f_id),              // work at EX 
    .ALUop_from_ID(ALUop_f_id),                         // work at EX
    .SignSelect_from_ID(SignSelect_f_id),                    //////////////////////
    .MemWrite_from_ID(MemWrite_f_id), 
    .MeMRead_from_ID(MeMRead_f_id),           // work at MEM   
    .RegWrite_from_ID(RegWrite_f_id), 
    .MeMtoReg_from_ID(MeMtoReg_f_id),          // work at WB
    // data
    .pc4_from_ID(pc4_f_IFID),                  // pc+4
    .inst_from_ID(inst_f_IFID),                 // instruction
    .Ext_imm_from_ID(SignImme_f_Sign),              //sign extend value
    .Ext_zero_from_ID(ZeroExtend_f_sign),
    .Data_from_rs(ReadData_rs_f_reg), 
    .Data_from_rt(ReadData_rt_f_reg),   // data from regs 
    .JalAddr_from_ID(JumpAddr_f_JAddr),                 //work at WB

    // output
    .branch_beq_2_EX(beq_f_id_ex), 
    .branch_bne_2_EX(bne_f_id_ex),     // work at MEM
    .JALFlush_2_EX(JALFlush_f_id_ex),                        // work at WB

    .ALUSrc_2_EX(ALUSrc_f_id_ex), 
    .RegDst_2_EX(RegDst_f_id_ex),               // work at EX 
    .ALUop_2_EX(ALUop_f_id_ex),                       // work at EX
    .SignSelect_2_EX(SignSelect_f_id_ex),
    .MemWrite_2_EX(MemWrite_f_id_ex), 
    .MeMRead_2_EX(MeMRead_f_id_ex),            // work at MEM   
    .RegWrite_2_EX(RegWrite_f_id_ex), 
    .MeMtoReg_2_EX(MeMtoReg_f_id_ex),           // work at WB

    .pc4_2_EX(pc4_f_id_ex),                        // pc+4
    .inst_2_EX(inst_f_id_ex),                       // instruction
    .Ext_imm_2_EX(Ext_imm_f_id_ex),                    //sign extend value
    .Ext_zero_2_EX(Ext_zero_f_id_ex),
    .Data_2_rs(Data_rs_f_id_ex), 
    .Data_2_rt(Data_rt_f_id_ex),             // data from regs 
    .JalAddr_2_EX(JalAddr_f_id_ex)
);

//******************
// EX part
// bne, beq address generate and back up pc8 for jal
AddrGenerate uut_jal_branch(
    .pc4_from_ID_EX(pc4_f_id_ex),
    .Ext_imm_from_ID_EX(Ext_imm_f_id_ex),
    .pc8_EX(pc8_f_ex),
    .AddrBranch(AddrBranch_f_ex)            //Address of bne,beq
);
// ALU 
// mux at input 1 of alu
mux3 uut_mux_in1_alu(
    .in0(Data_rs_f_id_ex), 
    .in1(wb_data_f_wb), 
    .in2(Res_f_ex_mem),
    .choose(ForwardA_f_forward),
    .lucky(alu1)
);
mux3 uut_mux_in2_alu(
    .in0(Data_rt_f_id_ex), 
    .in1(wb_data_f_wb), 
    .in2(Res_f_ex_mem),
    .choose(ForwardB_f_forward),
    .lucky(alu2_1)
);
mux2 uut_mux2_alu(
    .in0(alu2_1), 
    .in1(alu2_sign_mux),
    .choose(ALUSrc_f_id_ex),
    .lucky(alu2_2)
);
mux2 uut_mux_sign(           // rt, decide the signed_extend or zero_extend
    .in0(Ext_zero_f_id_ex), 
    .in1(Ext_imm_f_id_ex),
    .choose(SignSelect_f_id_ex),
    .lucky(alu2_sign_mux)
);
ALU uut_alu(
    .rs(alu1),  //也作为访存指令中的base
    .rt(alu2_2),
    .sa(inst_f_id_ex[10:6]),   // ins[10:6] of R type    
    .ALUop(ALUop_f_id_ex),
    .FuncCode(inst_f_id_ex[5:0]),
    .rd(rd_f_alu),  //more generally, it is just ALUout
    .Zero(Zero_f_alu), 
    .overflow(overflow_f_alu)
);
mux2_5 uut_wbAddrSelect(
    .in0(inst_f_id_ex[20:16]),    // rt
    .in1(inst_f_id_ex[15:11]),    // rd
    .choose(RegDst_f_id_ex),
    .lucky(rd_f_mux)
);
Forward uut_forward(
    .rt_from_ID_EX(inst_f_id_ex[20:16]), 
    .rs_from_ID_EX(inst_f_id_ex[25:21]),
    .rd_from_EX_MEM(rd_f_ex_mem), 
    .rd_from_MEM_WB(rd_f_mem_wb),
    .EX_MEM_RegWrite(RegWrite_f_ex_mem), 
    .MEM_WB_RegWrite(RegWrite_f_mem_wb),
    .ForwardA(ForwardA_f_forward), 
    .ForwardB(ForwardB_f_forward)
);
EXMEM uut_ex_mem(
    .clk(clk),.rst(rst),
    .JALFlush_from_WB(JALFlush_f_wb),   // flush IDEX regiater
    .PCScr_from_MEM(Pcscr_f_mem),

    // control signals
    .branch_beq_from_EX(beq_f_id_ex), 
    .branch_bne_from_EX(bne_f_id_ex),      // work at MEM
    .JALFlush_from_EX(JALFlush_f_id_ex),                            // work at WB

    .MemWrite_from_EX(MemWrite_f_id_ex), 
    .MeMRead_from_EX(MeMRead_f_id_ex),           // work at MEM   
    .RegWrite_from_EX(RegWrite_f_id_ex), 
    .MeMtoReg_from_EX(MeMtoReg_f_id_ex),          // work at WB
    
    // data
    .JalAddr_from_EX(JalAddr_f_id_ex),                 // work at WB    
    .pc8_from_Ex(pc8_f_ex),                     // work at WB    
    .rd_from_mux(rd_f_mux),                     // work at WB
    .overflow_from_ALU(overflow_f_alu),                     // work at WB
    .zero_from_ALU(Zero_f_alu),                         // work at MEM
    .BranchAddr_from_EX(AddrBranch_f_ex),              // address of bne,beq,work at MEM
    .Res_from_ALU(rd_f_alu),                    // work at MEM
    .Data_rt_from_EX(alu2_1),                 // work at MEM, to Dcache
    
    // out     
    .beq_2_MEM(beq_f_ex_mem), 
    .bne_2_MEM(bne_f_ex_mem),                  // work at MEM
    .JALFlush_2_MEM(JALFlush_f_ex_mem),
    .MemWrite_2_MEM(MemWrite_f_ex_mem), 
    .MeMRead_2_MEM(MeMRead_f_ex_mem),           // work at MEM   
    .RegWrite_2_MEM(RegWrite_f_ex_mem), 
    .MeMtoReg_2_MEM(MeMtoReg_f_ex_mem),          // work at WB
    .JalAddr_2_MEM(JalAddr_f_ex_mem),                 // work at WB    
    .pc8_2_MEM(pc8_f_ex_mem),                     // work at WB    
    .rd_2_MEM(rd_f_ex_mem),                      // work at WB
    .overflow_2_MEM(overflow_f_ex_mem),                      // work at WB
    .zero_2_MEM(zero_f_ex_mem),                          // work at MEM
    .BranchAddr_2_MEM(BranchAddr_f_ex_mem),              // address of bne,beq,work at MEM
    .Res_2_MEM(Res_f_ex_mem),                     // work at MEM
    .Data_rt_2_MEM(Data_rt_f_ex_mem)                  // work at MEM, to Dcache
);

//*************
// MEM
PCscr uut_pcscr(
    .bne_EX_MEM(bne_f_ex_mem), 
    .beq_EX_MEM(beq_f_ex_mem),
    .zero_EX_MEM(zero_f_ex_mem),
    .Pcscr(Pcscr_f_mem)
);
dcache uut_dcache(
    .clk(clk),.reset(rst),
    .we(MemWrite_f_ex_mem),
    .re(MeMRead_f_ex_mem),
    .addr(Res_f_ex_mem),
    .wdata(Data_rt_f_ex_mem),
    .rdata(rdata_f_dcache)
);
MEMWB uut_mem_wb(
    .clk(clk), .rst(rst),
    .JALFlush_from_WB(JALFlush_f_wb),   // flush IDEX regiater
    // control signals    
    .JALFlush_from_MEM(JALFlush_f_ex_mem),                            // work at WB  
    .RegWrite_from_MEM(RegWrite_f_ex_mem), 
    .MeMtoReg_from_MEM(MeMtoReg_f_ex_mem),          // work at WB
    
    // data
    .JalAddr_from_MEM(JalAddr_f_ex_mem),                 // work at WB    
    .pc8_from_MEM(pc8_f_ex_mem),                     // work at WB    
    .rd_from_MEM(rd_f_ex_mem),                      // work at WB
    .Res_from_MEM(Res_f_ex_mem),                     // work at WB
    .overflow_from_MEM(overflow_f_ex_mem),                      // work at WB
    .Data_from_dcache(rdata_f_dcache),                 // work at WB

    // out
    .JALFlush_2_WB(JALFlush_f_mem_wb),                            // work at WB  
    .RegWrite_2_WB(RegWrite_f_mem_wb), 
    .MeMtoReg_2_WB(MeMtoReg_f_mem_wb),          // work at WB
    
    // data
    .JalAddr_2_WB(JalAddr_f_mem_wb),                 // work at WB    
    .pc8_2_WB(pc8_f_mem_wb),                     // work at WB    
    .rd_2_WB(rd_f_mem_wb),                      // work at WB
    .Res_2_WB(Res_f_mem_wb),                     // work at WB
    .overflow_2_WB(overflow_f_mem_wb),                      // work at WB
    .Data_2_WB(Data_f_mem_wb)                  // work at WB    
);
WB uut_wb(
    // control signals    
    .JALFlush_from_MEM_WB(JALFlush_f_mem_wb),                            // work at WB  
    .RegWrite_from_MEM_WB(RegWrite_f_mem_wb), 
    .MeMtoReg_from_MEM_WB(MeMtoReg_f_mem_wb),          // work at WB
    
    // data
    .JalAddr_from_MEM_WB(JalAddr_f_mem_wb),                 // work at WB    
    .pc8_from_MEM_WB(pc8_f_mem_wb),                     // work at WB    
    .rd_from_MEM_WB(rd_f_mem_wb),                      // work at WB
    .Res_from_MEM_WB(Res_f_mem_wb),                     // work at WB
    .overflow_from_MEM_WB(overflow_f_mem_wb),                      // work at WB
    .Data_from_MEM_WB(Data_f_mem_wb),                 // work at WB

    .Regwrite_2_regs(Regwrite_f_wb),
    .JALFlush_2_IF(JALFlush_f_wb),
    .JalAddr_2_IF(JalAddr_f_wb),
    .wb_data(wb_data_f_wb),
    .wb_addr(wb_addr_f_wb)
);

endmodule

//
// Instruction Fetch
//
module IF(
    input clk, rst,
    input jr_from_id, j_from_id, Pcscr_from_mem, jal_from_wb,
    input [31:0] JrAddr_f_id, JAddr_f_id, JalAddr_f_wb, PscrAddr_f_mem,
    input PCwait,
    output [31:0] inst,
    output [31:0] PCout4    
);
// wire form if
wire [31:0] pc_mux_reg;
wire [31:0] pc4_reg_mux;
wire [31:0] PCout;

assign PCout4 = pc4_reg_mux;
pcmux uut_pcmux(
    .jr(jr_from_id), .j(j_from_id), .Pcscr(Pcscr_from_mem), .jal(jal_from_wb),
    .pc4(pc4_reg_mux), .JrAddr(JrAddr_f_id), .JAddr(JAddr_f_id), .JalAddr(JalAddr_f_wb),
    .PscrAddr(PscrAddr_f_mem), .CurrentPC(pc_mux_reg)
);
PCreg uut_PCreg(
    .clk(clk), .rst(rst),
    .PCwait(PCwait),       //keep the PC value when pipeline stall
    .PCin(pc_mux_reg),
    .PCout(PCout),
    .PCout4(pc4_reg_mux)
);
icache uut_ica(
	.rst(rst),
	.pc(PCout),
	.inst(inst)
);
endmodule

module pcmux(
    input jr, j, Pcscr, jal,
    input [31:0] pc4, JrAddr, JAddr, JalAddr, PscrAddr,
    output [31:0] CurrentPC
);
wire [31:0] w1, w2, w3;

assign w1 = (jr)? JrAddr:pc4;
assign w2 = (j)?  JAddr:w1;
assign w3 = (Pcscr)? PscrAddr:w2;
assign CurrentPC = (jal)? JalAddr:w3;
endmodule

module mux3(
    input [31:0] in0, in1, in2,
    input [1:0] choose,
    output reg[31:0] lucky
);
always@(*) begin
    case(choose)
         2'b00,2'b11: lucky <= in0;
         2'b01: lucky <= in1;
         2'b10: lucky <= in2;
    endcase
end
endmodule

module mux2(
    input [31:0] in0, in1,
    input choose,
    output [31:0] lucky
);
assign lucky = (choose)? in1:in0;
endmodule

module mux2_5(
    input [4:0] in0, in1,
    input choose,
    output [4:0] lucky
);
assign lucky = (choose)? in1:in0;
endmodule


module ALU(
    input [31:0] rs,  //也作为访存指令中的base
    input [31:0] rt,
    input [4:0] sa,   // ins[10:6] of R type    
    input [2:0] ALUop,
    input [5:0] FuncCode,
    output reg [31:0] rd,  //more generally, it is just ALUout
    output wire Zero, 
    output reg overflow
);

//这里溢出还需要解决，ADD和ADDi以及Sub都需要解决溢出
//不写入问题，如何控制溢出的信号？

reg [3:0] ALUCtl;

assign Zero = (rd==0); //zero is true if rd is 0

//Generate ALUCtl by ALUop form Control unit
always @(*)begin
case(ALUop)
   3'b000,3'b111:  ALUCtl <= 4'b0010;   // add   
   3'b001:  ALUCtl <= 4'b0110;   // sub
   3'b010:begin                  // R type
          case(FuncCode)
          6'b100000,6'b100001: ALUCtl <= 4'b0010;   // add
          6'b100010: ALUCtl <= 4'b0110;   // sub
          6'b100100: ALUCtl <= 4'b0000;   // and
          6'b100101: ALUCtl <= 4'b0001;   // or
          6'b100110: ALUCtl <= 4'b0100;   // xor
          6'b100111: ALUCtl <= 4'b1100;   // nor
          6'b101010: ALUCtl <= 4'b0111;   // slt
          6'b000000: ALUCtl <= 4'b0011;   // sll
          6'b000010: ALUCtl <= 4'b1000;   // srl
          default: ALUCtl <= 4'b1111;     // should not happen 
          endcase
   end
   3'b011: ALUCtl <= 4'b0001;   // or
   3'b100: ALUCtl <= 4'b0000;   // and
   3'b101: ALUCtl <= 4'b0100;   // xor
   3'b110: ALUCtl <= 4'b1110;   //lui
   default: ALUCtl <= 4'b1111;     // should not happen 
endcase
end

always @(*) begin
    case (ALUCtl)
    4'b0000: rd <= rs & rt;  //and
    4'b0001: rd <= rs | rt;  //or
    4'b0010: rd <= rs + rt;  //add
    4'b0100: rd <= rs ^ rt;  //xor
    4'b0110: rd <= rs - rt;  //sub
    4'b0111: rd <= rs < rt? 1:0;  //is ture if rs is smaller
    4'b1100: rd <= ~(rs | rt);    //result is nor
    4'b0011: rd <= rt << sa;      // left shift sa bit
    4'b1000: rd <= rt >> sa;      // right shift sa bit
    4'b1110: rd <= {rt[15:0],16'b0}; // Lui instruction
    default: rd <= 0;
    endcase
end

always@(*)begin
    case(ALUop)
    3'b010:begin
        case(FuncCode)
        6'b100000: overflow <= rd[31] ^ rd[30];   // add
        6'b100010: overflow <= rd[31] ^ rd[30];   // sub
        default: overflow <= 1'b0;
        endcase
    end
    3'b111: overflow <= rd[31] ^ rd[30];   //addi
    default:overflow <= 1'b0;
    endcase
end
endmodule

module AddrGenerate(
    input [31:0] pc4_from_ID_EX,
    input [31:0] Ext_imm_from_ID_EX,
    output [31:0] pc8_EX,
    output [31:0] AddrBranch            //Address of bne,beq
);
wire [31:0] shift;
assign shift = {Ext_imm_from_ID_EX[29:0],2'b0};    // left shift 2bit
assign AddrBranch = shift + pc4_from_ID_EX;
assign pc8_EX = pc4_from_ID_EX + 32'd4;
endmodule

module EXMEM(
    input clk,rst,
    input JALFlush_from_WB,   // flush IDEX regiater
    input PCScr_from_MEM,

    // control signals
    input branch_beq_from_EX, branch_bne_from_EX,      // work at MEM
    input JALFlush_from_EX,                            // work at WB

    input MemWrite_from_EX, MeMRead_from_EX,           // work at MEM   
    input RegWrite_from_EX, MeMtoReg_from_EX,          // work at WB
    
    // data
    input [31:0] JalAddr_from_EX,                 // work at WB    
    input [31:0] pc8_from_Ex,                     // work at WB    
    input [4:0]  rd_from_mux,                     // work at WB
    input  overflow_from_ALU,                     // work at WB
    input  zero_from_ALU,                         // work at MEM
    input [31:0] BranchAddr_from_EX,              // address of bne,beq,work at MEM
    input [31:0] Res_from_ALU,                    // work at MEM
    input [31:0] Data_rt_from_EX,                 // work at MEM, to Dcache
    
    // out     
    output reg beq_2_MEM, bne_2_MEM,                  // work at MEM
    output reg JALFlush_2_MEM,                          // work at WB

    output reg MemWrite_2_MEM, MeMRead_2_MEM,           // work at MEM   
    output reg RegWrite_2_MEM, MeMtoReg_2_MEM,          // work at WB

    output reg [31:0] JalAddr_2_MEM,                 // work at WB    
    output reg [31:0] pc8_2_MEM,                     // work at WB    
    output reg [4:0]  rd_2_MEM,                      // work at WB
    output reg  overflow_2_MEM,                      // work at WB
    output reg  zero_2_MEM,                          // work at MEM
    output reg [31:0] BranchAddr_2_MEM,              // address of bne,beq,work at MEM
    output reg [31:0] Res_2_MEM,                     // work at MEM
    output reg [31:0] Data_rt_2_MEM                  // work at MEM, to Dcache
);

always@(posedge clk or negedge rst)begin
    if(!rst)begin
        beq_2_MEM <= 1'b0; 
        bne_2_MEM <= 1'b0;                             // work at MEM
        JALFlush_2_MEM <= 1'b0;                          // work at WB

        MemWrite_2_MEM <= 1'b0; 
        MeMRead_2_MEM <= 1'b0;           // work at MEM   
        RegWrite_2_MEM <= 1'b0; 
        MeMtoReg_2_MEM <= 1'b0;          // work at WB

        JalAddr_2_MEM <= 32'd0;                 // work at WB    
        pc8_2_MEM <= 32'd0;                     // work at WB    
        rd_2_MEM <= 5'd0;                      // work at WB
        overflow_2_MEM <= 1'd0;                      // work at WB
        zero_2_MEM <= 1'd0;                          // work at MEM
        BranchAddr_2_MEM <= 32'd0;              // address of bne,beq,work at MEM
        Res_2_MEM <= 32'd0;                     // work at MEM
        Data_rt_2_MEM <= 32'd0;
    end
    else if(JALFlush_from_WB|PCScr_from_MEM)begin
        beq_2_MEM <= 1'b0; 
        bne_2_MEM <= 1'b0;                             // work at MEM
        JALFlush_2_MEM <= 1'b0;                          // work at WB

        MemWrite_2_MEM <= 1'b0; 
        MeMRead_2_MEM <= 1'b0;           // work at MEM   
        RegWrite_2_MEM <= 1'b0; 
        MeMtoReg_2_MEM <= 1'b0;          // work at WB

        JalAddr_2_MEM <= 32'd0;                 // work at WB    
        pc8_2_MEM <= 32'd0;                     // work at WB    
        rd_2_MEM <= 5'd0;                      // work at WB
        overflow_2_MEM <= 1'd0;                      // work at WB
        zero_2_MEM <= 1'd0;                          // work at MEM
        BranchAddr_2_MEM <= 32'd0;              // address of bne,beq,work at MEM
        Res_2_MEM <= 32'd0;                     // work at MEM
        Data_rt_2_MEM <= 32'd0;

    end
    else begin
        beq_2_MEM <= branch_beq_from_EX; 
        bne_2_MEM <= branch_bne_from_EX;                    // work at MEM
        JALFlush_2_MEM <= JALFlush_from_EX;                   // work at WB

        MemWrite_2_MEM <= MemWrite_from_EX; 
        MeMRead_2_MEM <= MeMRead_from_EX;                     // work at MEM   
        RegWrite_2_MEM <= RegWrite_from_EX; 
        MeMtoReg_2_MEM <= MeMtoReg_from_EX;                   // work at WB

        JalAddr_2_MEM <= JalAddr_from_EX;             // work at WB    
        pc8_2_MEM <= pc8_from_Ex;                     // work at WB    
        rd_2_MEM <= rd_from_mux;                      // work at WB
        overflow_2_MEM <= overflow_from_ALU;                  // work at WB
        zero_2_MEM <= zero_from_ALU;                          // work at MEM
        BranchAddr_2_MEM <= BranchAddr_from_EX;               // address of bne,beq,work at MEM
        Res_2_MEM <= Res_from_ALU;                     // work at MEM
        Data_rt_2_MEM <= Data_rt_from_EX;
    end
end
endmodule

module Forward(
    input [4:0] rt_from_ID_EX, rs_from_ID_EX,
    input [4:0] rd_from_EX_MEM, rd_from_MEM_WB,
    input EX_MEM_RegWrite, MEM_WB_RegWrite,
    output reg [1:0] ForwardA, ForwardB
);

wire EXDectA, EXDectB,MEMDectA, MEMDectB;

// forward A
assign EXDectA = EX_MEM_RegWrite 
                & (rd_from_EX_MEM!=5'd0)
                & (rd_from_EX_MEM == rs_from_ID_EX);
assign MEMDectA = MEM_WB_RegWrite 
                & (rd_from_MEM_WB != 5'd0)
                & (~EXDectA) 
                &(rd_from_MEM_WB==rs_from_ID_EX);
// forward B
assign EXDectB = EX_MEM_RegWrite 
                & (rd_from_EX_MEM!=5'd0)
                & (rd_from_EX_MEM == rt_from_ID_EX);
assign MEMDectB = MEM_WB_RegWrite 
                & (rd_from_MEM_WB != 5'd0)
                & (~EXDectB) 
                &(rd_from_MEM_WB==rt_from_ID_EX);

always@(*)begin
    if(EXDectA)begin
           ForwardA <= 2'b10;
    end
    else if(MEMDectA)begin
        ForwardA <= 2'b01;
    end 
    else ForwardA <= 2'b00;
end

always@(*)begin
    if(EXDectB)begin
           ForwardB <= 2'b10;
    end
    else if(MEMDectB)begin
        ForwardB <= 2'b01;
    end 
    else ForwardB <= 2'b00;
end
endmodule

module HazardDetext(
    input MeMRead_from_ID_EX,
    input [4:0] rt_from_ID_EX,
    input [4:0] rs_from_IF_ID, rt_from_IF_ID,
    output IFIDWait, PCwait, Detect_to_Control
);
wire Stall;
assign Stall = MeMRead_from_ID_EX
             &((rt_from_ID_EX==rs_from_IF_ID)|(rt_from_ID_EX==rt_from_IF_ID));

assign IFIDWait = (Stall)? 1'b1:1'b0;
assign PCwait = (Stall)? 1'b1:1'b0;     
assign Detect_to_Control = (Stall)? 1'b1:1'b0;
endmodule

module IDEX(
    input clk, rst, 
    input JALFlush_from_WB,   // flush IDEX regiater
    input PCScr_from_MEM,

    // control signals
    input branch_beq_from_ID, branch_bne_from_ID,      // work at MEM
    input JALFlush_from_ID,                            // work at WB

    input ALUSrc_from_ID, RegDst_from_ID,              // work at EX 
    input [2:0] ALUop_from_ID,                         // work at EX
    input SignSelect_from_ID,
    input MemWrite_from_ID, MeMRead_from_ID,           // work at MEM   
    input RegWrite_from_ID, MeMtoReg_from_ID,          // work at WB
    // data
    input [31:0] pc4_from_ID,                  // pc+4
    input [31:0] inst_from_ID,                 // instruction
    input [31:0] Ext_imm_from_ID,              //sign extend value
    input [31:0] Ext_zero_from_ID,
    input [31:0] Data_from_rs, Data_from_rt,   // data from regs 
    input [31:0] JalAddr_from_ID,                 //work at WB

    // output
    output reg branch_beq_2_EX, branch_bne_2_EX,     // work at MEM
    output reg JALFlush_2_EX,                        // work at WB

    output reg ALUSrc_2_EX, RegDst_2_EX,               // work at EX 
    output reg [2:0] ALUop_2_EX,                       // work at EX
    output reg SignSelect_2_EX,                             // work at EX

    output reg MemWrite_2_EX, MeMRead_2_EX,            // work at MEM   
    output reg RegWrite_2_EX, MeMtoReg_2_EX,           // work at WB

    output reg [31:0] pc4_2_EX,                        // pc+4
    output reg [31:0] inst_2_EX,                       // instruction
    output reg [31:0] Ext_imm_2_EX,                    //sign extend value
    output reg [31:0] Ext_zero_2_EX,
    output reg [31:0] Data_2_rs, Data_2_rt,             // data from regs 
    output reg [31:0] JalAddr_2_EX
);

always@(posedge clk or negedge rst)begin
    if(!rst)begin
        branch_beq_2_EX <= 1'b0; 
        branch_bne_2_EX <= 1'b0;     
        JALFlush_2_EX <= 1'b0;        // branch instruction

        ALUSrc_2_EX <= 1'b0;
        RegDst_2_EX <= 1'b0; 
        SignSelect_2_EX <= 1'b0;                    
        MemWrite_2_EX <= 1'b0; 
        MeMRead_2_EX <= 1'b0;            
        RegWrite_2_EX <= 1'b0; 
        MeMtoReg_2_EX <= 1'b0;
        pc4_2_EX <= 32'd0;                  
        inst_2_EX <= 32'd0;                       
        Ext_imm_2_EX <= 32'd0; 
        Ext_zero_2_EX <= 32'b0;                  
        Data_2_rs <= 32'd0; 
        Data_2_rt <= 32'd0; 
        JalAddr_2_EX <= 32'b0;              
        ALUop_2_EX <= 3'b011;  
    end
    else if(JALFlush_from_WB|PCScr_from_MEM)begin
        branch_beq_2_EX <= 1'b0; 
        branch_bne_2_EX <= 1'b0;     
        JALFlush_2_EX <= 1'b0;        // branch instruction

        ALUSrc_2_EX <= 1'b0;
        RegDst_2_EX <= 1'b0; 
        SignSelect_2_EX <= 1'b0;                    
        MemWrite_2_EX <= 1'b0; 
        MeMRead_2_EX <= 1'b0;            
        RegWrite_2_EX <= 1'b0; 
        MeMtoReg_2_EX <= 1'b0;
        pc4_2_EX <= 32'd0;                  
        inst_2_EX <= 32'd0;                       
        Ext_imm_2_EX <= 32'd0; 
        Ext_zero_2_EX <= 32'b0;                  
        Data_2_rs <= 32'd0; 
        Data_2_rt <= 32'd0; 
        JalAddr_2_EX <= 32'b0;              
        ALUop_2_EX <= 3'b011;  
    end
    else begin
        branch_beq_2_EX <= branch_beq_from_ID; 
        branch_bne_2_EX <= branch_bne_from_ID;     
        JALFlush_2_EX <= JALFlush_from_ID;
        ALUSrc_2_EX <= ALUSrc_from_ID;
        RegDst_2_EX <= RegDst_from_ID; 
        SignSelect_2_EX <= SignSelect_from_ID;                    
        MemWrite_2_EX <= MemWrite_from_ID; 
        MeMRead_2_EX <= MeMRead_from_ID;            
        RegWrite_2_EX <= RegWrite_from_ID; 
        MeMtoReg_2_EX <= MeMtoReg_from_ID;
        pc4_2_EX <= pc4_from_ID;                  
        inst_2_EX <= inst_from_ID;                       
        Ext_imm_2_EX <= Ext_imm_from_ID;  
        Ext_zero_2_EX <= Ext_zero_from_ID;                
        Data_2_rs <= Data_from_rs; 
        Data_2_rt <= Data_from_rt;  
        JalAddr_2_EX <= JalAddr_from_ID;              
        ALUop_2_EX <= ALUop_from_ID; 
    end
end
endmodule

module IFID(
    input clk, rst, IFIDFlush,       // IFIDFlush clear signals
    input IFIDWait,                  // IFIDWait keep signals
    input JRFlush_from_ID,
    input JFlush_from_ID,
    input JALFlush_from_WB,
    input PCScr,
    input [31:0] inst_from_IF,       // current instruction
    input [31:0] pc4_form_IF,        // next pc value
    output reg [31:0] pc4_to_ID, inst_to_ID
);

//wire IFIDWait_temp, JRFlush_temp, Jflush_temp, Jalflush_temp, Pcscr_temp;
//wire [31:0] inst_temp1, pc4_temp1,inst_temp2, pc4_temp2;

//assign inst_temp1 = (IFIDFlush|JRFlush_from_ID|JALFlush_from_WB|JFlush_from_ID|PCScr)?  32'b0:inst_from_IF;
//assign pc4_temp1 = (IFIDFlush|JRFlush_from_ID|JALFlush_from_WB|JFlush_from_ID|PCScr)?  32'b0:pc4_form_IF;

//assign inst_temp2 = (IFIDWait)?  pc4_to_ID:inst_temp1;
//assign pc4_temp2 = (IFIDWait)?  inst_to_ID:pc4_temp1;

always@(posedge clk or negedge rst)begin
    if(!rst)
    begin
        pc4_to_ID <= 32'b0;
        inst_to_ID <= 32'b0;
    end 
    else if(IFIDFlush|JRFlush_from_ID|JALFlush_from_WB|JFlush_from_ID|PCScr)begin
        pc4_to_ID <= 32'b0;
        inst_to_ID <= 32'b0;
    end
    else if(!IFIDWait) begin
         pc4_to_ID <= pc4_form_IF;
        inst_to_ID <= inst_from_IF;
    end
    else begin
        pc4_to_ID <= pc4_to_ID;
        inst_to_ID <= inst_to_ID;
    end
end
endmodule

module IdJumpAddr(
    input [25:0] instr_index_of_inst,
    input [31:0]  Pc4_from_IF_ID,
    output [31:0] JumpAddr_to_IF
);

assign JumpAddr_to_IF = {Pc4_from_IF_ID[31:28],instr_index_of_inst[25:0],2'b0};
endmodule

module MEMWB(
    input clk, rst,
    input JALFlush_from_WB,   // flush IDEX regiater

    // control signals    
    input JALFlush_from_MEM,                            // work at WB  
    input RegWrite_from_MEM, MeMtoReg_from_MEM,          // work at WB
    
    // data
    input [31:0] JalAddr_from_MEM,                 // work at WB    
    input [31:0] pc8_from_MEM,                     // work at WB    
    input [4:0]  rd_from_MEM,                      // work at WB
    input [31:0] Res_from_MEM,                     // work at WB
    input  overflow_from_MEM,                      // work at WB
    input [31:0] Data_from_dcache,                 // work at WB

    // out
    output reg JALFlush_2_WB,                            // work at WB  
    output reg RegWrite_2_WB, MeMtoReg_2_WB,          // work at WB
    
    // data
    output reg [31:0] JalAddr_2_WB,                 // work at WB    
    output reg [31:0] pc8_2_WB,                     // work at WB    
    output reg [4:0]  rd_2_WB,                      // work at WB
    output reg [31:0] Res_2_WB,                     // work at WB
    output reg  overflow_2_WB,                      // work at WB
    output reg [31:0] Data_2_WB                  // work at WB    
);
always@(posedge clk or negedge rst)begin
    if(!rst)begin
        JALFlush_2_WB <= 1'b0;                             // work at WB  
        RegWrite_2_WB <= 1'b0; 
        MeMtoReg_2_WB <= 1'b0;  
        JalAddr_2_WB <= 32'd0;                 // work at WB    
        pc8_2_WB <= 32'd0;                    // work at WB    
        rd_2_WB <= 5'd0;                      // work at WB
        Res_2_WB <= 32'd0;                     // work at WB
        overflow_2_WB <= 1'd0;                      // work at WB
        Data_2_WB  <= 32'd0;
    end else begin
        JALFlush_2_WB <= JALFlush_from_MEM;                             // work at WB  
        RegWrite_2_WB <= RegWrite_from_MEM; 
        MeMtoReg_2_WB <= MeMtoReg_from_MEM;  
        JalAddr_2_WB <= JalAddr_from_MEM;                 // work at WB    
        pc8_2_WB <= pc8_from_MEM;                    // work at WB    
        rd_2_WB <= rd_from_MEM;                      // work at WB
        Res_2_WB <= Res_from_MEM;                     // work at WB
        overflow_2_WB <= overflow_from_MEM;                      // work at WB
        Data_2_WB  <= Data_from_dcache;
    end
end

endmodule

module MIPSControl(
    input [31:0] inst_from_IF_ID,
    input clk, rst,
    input Detect_to_Control,               // clear signals when it is true
    
    output reg JRFlush, JFlush,            // Jump signals,work at ID
    output reg branch_beq, branch_bne,     // work at MEM
    output reg JALFlush,                   // work at WB

    output reg ALUSrc, RegDst,             // work at EX 
    output reg [2:0] ALUop,                // work at EX
    output reg MemWrite, MeMRead,          // work at MEM   
    output reg RegWrite, MeMtoReg,         // work at WB
    output reg SignSelect                  // work at EX
);
wire [5:0] Opcode;
wire [5:0] Funcode;
assign Opcode = inst_from_IF_ID[31:26];
assign Funcode = inst_from_IF_ID[5:0];

always@(*)begin
    if(Detect_to_Control==1)begin
        MemWrite <= 1'b0; 
        MeMRead <= 1'b0;
        RegWrite <= 1'b0; 
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0; 
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;      
    end else begin
    case(Opcode)
    6'b000000:begin      // R type
    // add,sub,and,or,xor,slt,sll,srl,nor,jr
        ALUop <= 3'b010;
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b1;       // address is rd
        ALUSrc <= 1'b0;       // read data2
        MemWrite <= 1'b0; 
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;
        MeMtoReg <= 1'b0;
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;
        SignSelect <= 1'b0;
        if(Funcode==6'b001000)JRFlush =1'b1;  // JR enable
        else JRFlush =1'b0; 
    end
    6'b100011:begin      // lw
        ALUop <= 3'b000;
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read offset
        MemWrite <= 1'b0; 
        MeMRead <= 1'b1;      // load data
        RegWrite <= 1'b1;
        MeMtoReg <= 1'b1;     // data from dcache
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b101011:begin      // sw
        ALUop <= 3'b000;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read offset
        MemWrite <= 1'b1;     // save data
        MeMRead <= 1'b0;
        RegWrite <= 1'b0;     // no need to write regs when sw
        MeMtoReg <= 1'b1;     // data from dcache    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b001000:begin     // addi
        ALUop <= 3'b111;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b001001:begin     //addiu
        ALUop <= 3'b000;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b001100:begin     // andi
        ALUop <= 3'b100;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b0;
    end
    6'b001101:begin      // ori
        ALUop <= 3'b011;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b0;
    end
    6'b001110:begin     // xori
        ALUop <= 3'b101;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b0;
    end
    6'b001111:begin     // lui
        ALUop <= 3'b110;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is rt
        ALUSrc <= 1'b1;       // read immediate
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b0;
    end
    6'b000100:begin      //beq
        ALUop <= 3'b001;        
        branch_beq <= 1'b1; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is immediate
        ALUSrc <= 1'b0;       // read rt
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b0;     // no need to write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b000101:begin      // bne
        ALUop <= 3'b001;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b1;        
        RegDst <= 1'b0;       // address is immediate
        ALUSrc <= 1'b0;       // read rt
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b0;     // no need to write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b000010:begin     // J
        ALUop <= 3'b001;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       // address is immediate
        ALUSrc <= 1'b0;       // read rt
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b0;     // no need to write regs 
        MeMtoReg <= 1'b0;     // data from ALU    
        JALFlush <= 1'b0; 
        JFlush <= 1'b1;       // J enable
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    6'b000011:begin     // Jal
        ALUop <= 3'b001;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       
        ALUSrc <= 1'b0;       
        MemWrite <= 1'b0;    
        MeMRead <= 1'b0;
        RegWrite <= 1'b1;     // need to write regs 
        MeMtoReg <= 1'b0;      
        JALFlush <= 1'b1;     // Jal enable
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    default:begin
        ALUop <= 3'b001;        
        branch_beq <= 1'b0; 
        branch_bne <= 1'b0;        
        RegDst <= 1'b0;       
        ALUSrc <= 1'b0;       
        MemWrite <= 1'b0;     // can't write cache
        MeMRead <= 1'b0;      // can't read cache
        RegWrite <= 1'b0;     // can't write regs 
        MeMtoReg <= 1'b0;      
        JALFlush <= 1'b0;    
        JFlush <= 1'b0;    
        JRFlush =1'b0;
        SignSelect <= 1'b1;
    end
    endcase
    end
end
endmodule

module Mux32_2(
    input [31:0] in1, in2,
    input clt,
    output wire [31:0] out
);
assign out = (clt)? in1:in2;
endmodule 

module Mux5_2(
    input [4:0] in1, in2,
    input clt,
    output wire [4:0] out
);
assign out = (clt)? in1:in2;
endmodule

module PCreg(
    input clk, rst,
    input PCwait,       //keep the PC value when pipeline stall
    input [31:0] PCin,
    output reg [31:0] PCout,
    output wire [31:0] PCout4
);
always@(posedge clk or negedge rst)begin
    if(!rst) PCout <= 32'b0;
    else if(PCwait==1) PCout <= PCout;
    else PCout <= PCin;
end

assign PCout4 = PCout + 32'd4;

endmodule

module PCscr(
    input bne_EX_MEM, beq_EX_MEM,
    input zero_EX_MEM,
    output Pcscr
);

assign Pcscr = (bne_EX_MEM &(~zero_EX_MEM))|(beq_EX_MEM & zero_EX_MEM);

endmodule

module Regs(
    input clk, rst, RegWrite,
    input [4:0] ReadAddr_rs, ReadAddr_rt,
    input [4:0] WriteAddr_rd,              //需要注意的是不同指令可能名称不同
    input [31:0] WriteData,
    output [31:0] ReadData_rs, ReadData_rt 
);
reg [31:0] RegRam[31:0];
integer  i;

always@(negedge clk or negedge rst)
begin
  if(!rst) begin
      for(i=0; i<32; i=i+1)begin
      RegRam[i] <= 0;
      end
  end else if(RegWrite==1)begin
      RegRam[WriteAddr_rd] <= WriteData;
  end 
end

assign ReadData_rs = ((RegWrite==1)&(WriteAddr_rd==ReadAddr_rs))? WriteData:RegRam[ReadAddr_rs];
assign ReadData_rt = ((RegWrite==1)&(WriteAddr_rd==ReadAddr_rt))? WriteData:RegRam[ReadAddr_rt];
    
endmodule

module SignExtend(
    input [15:0] imme_of_inst,
    output [31:0] SignImme, ZeroExtend
);
assign SignImme = {{16{imme_of_inst[15]}},imme_of_inst[15:0]};
assign ZeroExtend = {16'b0,imme_of_inst[15:0]};
endmodule

module WB(
    // control signals    
    input JALFlush_from_MEM_WB,                            // work at WB  
    input RegWrite_from_MEM_WB, MeMtoReg_from_MEM_WB,          // work at WB
    
    // data
    input [31:0] JalAddr_from_MEM_WB,                 // work at WB    
    input [31:0] pc8_from_MEM_WB,                     // work at WB    
    input [4:0]  rd_from_MEM_WB,                      // work at WB
    input [31:0] Res_from_MEM_WB,                     // work at WB
    input  overflow_from_MEM_WB,                      // work at WB
    input [31:0] Data_from_MEM_WB,                 // work at WB

    output Regwrite_2_regs,
    output JALFlush_2_IF,
    output [31:0] JalAddr_2_IF,
    output [31:0] wb_data,
    output [4:0] wb_addr
);

wire [31:0] wb2_data;
assign wb2_data = (MeMtoReg_from_MEM_WB)? Data_from_MEM_WB:Res_from_MEM_WB;
// if memtoreg is ture, dcache give data, else alu
assign Regwrite_2_regs = RegWrite_from_MEM_WB & (~overflow_from_MEM_WB);

assign wb_data = (JALFlush_from_MEM_WB)? pc8_from_MEM_WB:wb2_data;
assign wb_addr = (JALFlush_from_MEM_WB)? 5'd31:rd_from_MEM_WB;

assign JALFlush_2_IF =JALFlush_from_MEM_WB;
assign JalAddr_2_IF =JalAddr_from_MEM_WB;
endmodule

module dcache(clk,reset,we,re,addr,wdata,rdata);
  input   clk, we,re;
  input reset;
  input[31:0]   addr, wdata;
  output[31:0]  rdata; 
  
  reg[31:0]   RAM[383:0]; 
 
  //assign rdata = re ? RAM[addr[31:0]]:0;
 
  assign rdata = re ? RAM[addr[8:0]]:0;
 
 
	always@(posedge clk or negedge reset)
	 begin
		if (~reset)
		begin
        RAM[0] <= 32'h00000063;
        RAM[1] <= 32'h0000007c;
        RAM[2] <= 32'h00000077;
        RAM[3] <= 32'h0000007b;
        RAM[4] <= 32'h000000f2;
        RAM[5] <= 32'h0000006b;
        RAM[6] <= 32'h0000006f;
        RAM[7] <= 32'h000000c5;
        RAM[8] <= 32'h00000030;
        RAM[9] <= 32'h00000001;
        RAM[10] <= 32'h00000067;
        RAM[11] <= 32'h0000002b;
        RAM[12] <= 32'h000000fe;
        RAM[13] <= 32'h000000d7;
        RAM[14] <= 32'h000000ab;
        RAM[15] <= 32'h00000076;
        RAM[16] <= 32'h000000ca;
        RAM[17] <= 32'h00000082;
        RAM[18] <= 32'h000000c9;
        RAM[19] <= 32'h0000007d;
        RAM[20] <= 32'h000000fa;
        RAM[21] <= 32'h00000059;
        RAM[22] <= 32'h00000047;
        RAM[23] <= 32'h000000f0;
        RAM[24] <= 32'h000000ad;
        RAM[25] <= 32'h000000d4;
        RAM[26] <= 32'h000000a2;
        RAM[27] <= 32'h000000af;
        RAM[28] <= 32'h0000009c;
        RAM[29] <= 32'h000000a4;
        RAM[30] <= 32'h00000072;
        RAM[31] <= 32'h000000c0;
        RAM[32] <= 32'h000000b7;
        RAM[33] <= 32'h000000fd;
        RAM[34] <= 32'h00000093;
        RAM[35] <= 32'h00000026;
        RAM[36] <= 32'h00000036;
        RAM[37] <= 32'h0000003f;
        RAM[38] <= 32'h000000f7;
        RAM[39] <= 32'h000000cc;
        RAM[40] <= 32'h00000034;
        RAM[41] <= 32'h000000a5;
        RAM[42] <= 32'h000000e5;
        RAM[43] <= 32'h000000f1;
        RAM[44] <= 32'h00000071;
        RAM[45] <= 32'h000000d8;
        RAM[46] <= 32'h00000031;
        RAM[47] <= 32'h00000015;
        RAM[48] <= 32'h00000004;
        RAM[49] <= 32'h000000c7;
        RAM[50] <= 32'h00000023;
        RAM[51] <= 32'h000000c3;
        RAM[52] <= 32'h00000018;
        RAM[53] <= 32'h00000096;
        RAM[54] <= 32'h00000005;
        RAM[55] <= 32'h0000009a;
        RAM[56] <= 32'h00000007;
        RAM[57] <= 32'h00000012;
        RAM[58] <= 32'h00000080;
        RAM[59] <= 32'h000000e2;
        RAM[60] <= 32'h000000eb;
        RAM[61] <= 32'h00000027;
        RAM[62] <= 32'h000000b2;
        RAM[63] <= 32'h00000075;
        RAM[64] <= 32'h00000009;
        RAM[65] <= 32'h00000083;
        RAM[66] <= 32'h0000002c;
        RAM[67] <= 32'h0000001a;
        RAM[68] <= 32'h0000001b;
        RAM[69] <= 32'h0000006e;
        RAM[70] <= 32'h0000005a;
        RAM[71] <= 32'h000000a0;
        RAM[72] <= 32'h00000052;
        RAM[73] <= 32'h0000003b;
        RAM[74] <= 32'h000000d6;
        RAM[75] <= 32'h000000b3;
        RAM[76] <= 32'h00000029;
        RAM[77] <= 32'h000000e3;
        RAM[78] <= 32'h0000002f;
        RAM[79] <= 32'h00000084;
        RAM[80] <= 32'h00000053;
        RAM[81] <= 32'h000000d1;
        RAM[82] <= 32'h00000000;
        RAM[83] <= 32'h000000ed;
        RAM[84] <= 32'h00000020;
        RAM[85] <= 32'h000000fc;
        RAM[86] <= 32'h000000b1;
        RAM[87] <= 32'h0000005b;
        RAM[88] <= 32'h0000006a;
        RAM[89] <= 32'h000000cb;
        RAM[90] <= 32'h000000be;
        RAM[91] <= 32'h00000039;
        RAM[92] <= 32'h0000004a;
        RAM[93] <= 32'h0000004c;
        RAM[94] <= 32'h00000058;
        RAM[95] <= 32'h000000cf;
        RAM[96] <= 32'h000000d0;
        RAM[97] <= 32'h000000ef;
        RAM[98] <= 32'h000000aa;
        RAM[99] <= 32'h000000fb;
        RAM[100] <= 32'h00000043;
        RAM[101] <= 32'h0000004d;
        RAM[102] <= 32'h00000033;
        RAM[103] <= 32'h00000085;
        RAM[104] <= 32'h00000045;
        RAM[105] <= 32'h000000f9;
        RAM[106] <= 32'h00000002;
        RAM[107] <= 32'h0000007f;
        RAM[108] <= 32'h00000050;
        RAM[109] <= 32'h0000003c;
        RAM[110] <= 32'h0000009f;
        RAM[111] <= 32'h000000a8;
        RAM[112] <= 32'h00000051;
        RAM[113] <= 32'h000000a3;
        RAM[114] <= 32'h00000040;
        RAM[115] <= 32'h0000008f;
        RAM[116] <= 32'h00000092;
        RAM[117] <= 32'h0000009d;
        RAM[118] <= 32'h00000038;
        RAM[119] <= 32'h000000f5;
        RAM[120] <= 32'h000000bc;
        RAM[121] <= 32'h000000b6;
        RAM[122] <= 32'h000000da;
        RAM[123] <= 32'h00000021;
        RAM[124] <= 32'h00000010;
        RAM[125] <= 32'h000000ff;
        RAM[126] <= 32'h000000f3;
        RAM[127] <= 32'h000000d2;
        RAM[128] <= 32'h000000cd;
        RAM[129] <= 32'h0000000c;
        RAM[130] <= 32'h00000013;
        RAM[131] <= 32'h000000ec;
        RAM[132] <= 32'h0000005f;
        RAM[133] <= 32'h00000097;
        RAM[134] <= 32'h00000044;
        RAM[135] <= 32'h00000017;
        RAM[136] <= 32'h000000c4;
        RAM[137] <= 32'h000000a7;
        RAM[138] <= 32'h0000007e;
        RAM[139] <= 32'h0000003d;
        RAM[140] <= 32'h00000064;
        RAM[141] <= 32'h0000005d;
        RAM[142] <= 32'h00000019;
        RAM[143] <= 32'h00000073;
        RAM[144] <= 32'h00000060;
        RAM[145] <= 32'h00000081;
        RAM[146] <= 32'h0000004f;
        RAM[147] <= 32'h000000dc;
        RAM[148] <= 32'h00000022;
        RAM[149] <= 32'h0000002a;
        RAM[150] <= 32'h00000090;
        RAM[151] <= 32'h00000088;
        RAM[152] <= 32'h00000046;
        RAM[153] <= 32'h000000ee;
        RAM[154] <= 32'h000000b8;
        RAM[155] <= 32'h00000014;
        RAM[156] <= 32'h000000de;
        RAM[157] <= 32'h0000005e;
        RAM[158] <= 32'h0000000b;
        RAM[159] <= 32'h000000db;
        RAM[160] <= 32'h000000e0;
        RAM[161] <= 32'h00000032;
        RAM[162] <= 32'h0000003a;
        RAM[163] <= 32'h0000000a;
        RAM[164] <= 32'h00000049;
        RAM[165] <= 32'h00000006;
        RAM[166] <= 32'h00000024;
        RAM[167] <= 32'h0000005c;
        RAM[168] <= 32'h000000c2;
        RAM[169] <= 32'h000000d3;
        RAM[170] <= 32'h000000ac;
        RAM[171] <= 32'h00000062;
        RAM[172] <= 32'h00000091;
        RAM[173] <= 32'h00000095;
        RAM[174] <= 32'h000000e4;
        RAM[175] <= 32'h00000079;
        RAM[176] <= 32'h000000e7;
        RAM[177] <= 32'h000000c8;
        RAM[178] <= 32'h00000037;
        RAM[179] <= 32'h0000006d;
        RAM[180] <= 32'h0000008d;
        RAM[181] <= 32'h000000d5;
        RAM[182] <= 32'h0000004e;
        RAM[183] <= 32'h000000a9;
        RAM[184] <= 32'h0000006c;
        RAM[185] <= 32'h00000056;
        RAM[186] <= 32'h000000f4;
        RAM[187] <= 32'h000000ea;
        RAM[188] <= 32'h00000065;
        RAM[189] <= 32'h0000007a;
        RAM[190] <= 32'h000000ae;
        RAM[191] <= 32'h00000008;
        RAM[192] <= 32'h000000ba;
        RAM[193] <= 32'h00000078;
        RAM[194] <= 32'h00000025;
        RAM[195] <= 32'h0000002e;
        RAM[196] <= 32'h0000001c;
        RAM[197] <= 32'h000000a6;
        RAM[198] <= 32'h000000b4;
        RAM[199] <= 32'h000000c6;
        RAM[200] <= 32'h000000e8;
        RAM[201] <= 32'h000000dd;
        RAM[202] <= 32'h00000074;
        RAM[203] <= 32'h0000001f;
        RAM[204] <= 32'h0000004b;
        RAM[205] <= 32'h000000bd;
        RAM[206] <= 32'h0000008b;
        RAM[207] <= 32'h0000008a;
        RAM[208] <= 32'h00000070;
        RAM[209] <= 32'h0000003e;
        RAM[210] <= 32'h000000b5;
        RAM[211] <= 32'h00000066;
        RAM[212] <= 32'h00000048;
        RAM[213] <= 32'h00000003;
        RAM[214] <= 32'h000000f6;
        RAM[215] <= 32'h0000000e;
        RAM[216] <= 32'h00000061;
        RAM[217] <= 32'h00000035;
        RAM[218] <= 32'h00000057;
        RAM[219] <= 32'h000000b9;
        RAM[220] <= 32'h00000086;
        RAM[221] <= 32'h000000c1;
        RAM[222] <= 32'h0000001d;
        RAM[223] <= 32'h0000009e;
        RAM[224] <= 32'h000000e1;
        RAM[225] <= 32'h000000f8;
        RAM[226] <= 32'h00000098;
        RAM[227] <= 32'h00000011;
        RAM[228] <= 32'h00000069;
        RAM[229] <= 32'h000000d9;
        RAM[230] <= 32'h0000008e;
        RAM[231] <= 32'h00000094;
        RAM[232] <= 32'h0000009b;
        RAM[233] <= 32'h0000001e;
        RAM[234] <= 32'h00000087;
        RAM[235] <= 32'h000000e9;
        RAM[236] <= 32'h000000ce;
        RAM[237] <= 32'h00000055;
        RAM[238] <= 32'h00000028;
        RAM[239] <= 32'h000000df;
        RAM[240] <= 32'h0000008c;
        RAM[241] <= 32'h000000a1;
        RAM[242] <= 32'h00000089;
        RAM[243] <= 32'h0000000d;
        RAM[244] <= 32'h000000bf;
        RAM[245] <= 32'h000000e6;
        RAM[246] <= 32'h00000042;
        RAM[247] <= 32'h00000068;
        RAM[248] <= 32'h00000041;
        RAM[249] <= 32'h00000099;
        RAM[250] <= 32'h0000002d;
        RAM[251] <= 32'h0000000f;
        RAM[252] <= 32'h000000b0;
        RAM[253] <= 32'h00000054;
        RAM[254] <= 32'h000000bb;
        RAM[255] <= 32'h00000016;
        RAM[256] <= 32'h00000000;
        RAM[257] <= 32'h00000000;
        RAM[258] <= 32'h00000000;
        RAM[259] <= 32'h00000000;
        RAM[260] <= 32'h3243f6a8;         // plaintext
        RAM[261] <= 32'h885a308d;
        RAM[262] <= 32'h313198a2;
        RAM[263] <= 32'he0370734;
        RAM[264] <= 32'h00000000;
        RAM[265] <= 32'h00000000;
        RAM[266] <= 32'h00000000;
        RAM[267] <= 32'h00000000;
        RAM[268] <= 32'h00000000;
        RAM[269] <= 32'h00000000;
        RAM[270] <= 32'h2b7e1516;        // key
        RAM[271] <= 32'h28aed2a6;
        RAM[272] <= 32'habf71588;
        RAM[273] <= 32'h09cf4f3c;
        RAM[274] <= 32'h00000000;
        RAM[275] <= 32'h00000000;
        RAM[276] <= 32'h00000000;
        RAM[277] <= 32'h00000000;
        RAM[278] <= 32'h00000000;
        RAM[279] <= 32'h00000000;
        RAM[280] <= 32'h00000000;
        RAM[281] <= 32'h00000000;
        RAM[282] <= 32'h00000000;
        RAM[283] <= 32'h00000000;
        RAM[284] <= 32'h00000000;
        RAM[285] <= 32'h00000000;
        RAM[286] <= 32'h00000000;
        RAM[287] <= 32'h00000000;
        RAM[288] <= 32'h00000000;
        RAM[289] <= 32'h00000000;
        RAM[290] <= 32'h00000000;
        RAM[291] <= 32'h00000000;
        RAM[292] <= 32'h00000000;
        RAM[293] <= 32'h00000000;
        RAM[294] <= 32'h00000000;
        RAM[295] <= 32'h00000000;
        RAM[296] <= 32'h00000000;
        RAM[297] <= 32'h00000000;
        RAM[298] <= 32'h00000000;
        RAM[299] <= 32'h00000000;
        RAM[300] <= 32'h00000000;
        RAM[301] <= 32'h00000000;
        RAM[302] <= 32'h00000000;
        RAM[303] <= 32'h00000000;
        RAM[304] <= 32'h00000000;
        RAM[305] <= 32'h00000000;
        RAM[306] <= 32'h00000000;
        RAM[307] <= 32'h00000000;
        RAM[308] <= 32'h00000000;
        RAM[309] <= 32'h00000000;
        RAM[310] <= 32'h00000000;
        RAM[311] <= 32'h00000000;
        RAM[312] <= 32'h00000000;
        RAM[313] <= 32'h00000000;
        RAM[314] <= 32'h00000000;
        RAM[315] <= 32'h00000000;
        RAM[316] <= 32'h00000000;
        RAM[317] <= 32'h00000000;
        RAM[318] <= 32'h00000000;
        RAM[319] <= 32'h00000000;
        RAM[320] <= 32'h01000000;          // RC
        RAM[321] <= 32'h02000000;
        RAM[322] <= 32'h04000000;
        RAM[323] <= 32'h08000000;
        RAM[324] <= 32'h10000000;
        RAM[325] <= 32'h20000000;
        RAM[326] <= 32'h40000000;
        RAM[327] <= 32'h80000000;
        RAM[328] <= 32'h1b000000;
        RAM[329] <= 32'h36000000;
        RAM[330] <= 32'h00000000;
        RAM[331] <= 32'h00000000;
        RAM[332] <= 32'h00000000;
        RAM[333] <= 32'h00000000;
        RAM[334] <= 32'h00000000;
        RAM[335] <= 32'h00000000;
        RAM[336] <= 32'h00000000;
        RAM[337] <= 32'h00000000;
        RAM[338] <= 32'h00000000;
        RAM[339] <= 32'h00000000;
        RAM[340] <= 32'h00000000;
        RAM[341] <= 32'h00000000;
        RAM[342] <= 32'h00000000;
        RAM[343] <= 32'h00000000;
        RAM[344] <= 32'h00000000;
        RAM[345] <= 32'h00000000;
        RAM[346] <= 32'h00000000;
        RAM[347] <= 32'h00000000;
        RAM[348] <= 32'h00000000;
        RAM[349] <= 32'h00000000;
        RAM[350] <= 32'h00000000;
        RAM[351] <= 32'h00000000;
        RAM[352] <= 32'h00000000;
        RAM[353] <= 32'h00000000;
        RAM[354] <= 32'h00000000;
        RAM[355] <= 32'h00000000;
        RAM[356] <= 32'h00000000;
        RAM[357] <= 32'h00000000;
        RAM[358] <= 32'h00000000;
        RAM[359] <= 32'h00000000;
        RAM[360] <= 32'h00000000;
        RAM[361] <= 32'h00000000;
        RAM[362] <= 32'h00000000;
        RAM[363] <= 32'h00000000;
        RAM[364] <= 32'h00000000;
        RAM[365] <= 32'h00000000;
        RAM[366] <= 32'h00000000;
        RAM[367] <= 32'h00000000;
        RAM[368] <= 32'h00000000;
        RAM[369] <= 32'h00000000;
        RAM[370] <= 32'h00000000;
        RAM[371] <= 32'h00000000;
        RAM[372] <= 32'h00000000;
        RAM[373] <= 32'h00000000;
        RAM[374] <= 32'h00000000;
        RAM[375] <= 32'h00000000;
        RAM[376] <= 32'h00000000;
        RAM[377] <= 32'h00000000;
        RAM[378] <= 32'h00000000;
        RAM[379] <= 32'h00000000;
        RAM[380] <= 32'h00000000;
        RAM[381] <= 32'h00000000;
        RAM[382] <= 32'h00000000;
        RAM[383] <= 32'h00000000;
		end
		else begin
			if(we)
				//RAM[addr[31:0]]<= wdata;  
				RAM[addr[8:0]]<= wdata; 
		end
	 end

	
endmodule

module icache(
	input rst,
	input [31:0] pc,
	output [31:0] inst
);

reg [31:0] _ROM [1023:0];
integer  i;

assign inst=_ROM[pc[11:2]];
//initial begin
//		$readmemh("/data2/class/lsg/lsg15/MIPS/mips.txt",_ROM);
//	end
always@(negedge rst) begin
// R type test
	_ROM[0] = 32'h3401_0110;
	_ROM[1] = 32'h3803_0010;
	_ROM[2] = 32'h0023_2024;
	_ROM[3] = 32'h0023_2824;
	_ROM[4] = 32'h0023_3024;
	_ROM[5] = 32'h0023_3824;
	_ROM[6] = 32'h3c01_0000;
	_ROM[7] = 32'h3421_ffff;
	_ROM[8] = 32'h0021_1020;
	_ROM[9] = 32'h2028_0e00;
	_ROM[10] = 32'h3c01_0000;
	_ROM[11] = 32'h3421_ffff;
	_ROM[12] = 32'h0021_4821;
	_ROM[13] = 32'h302a_1234;
	_ROM[14] = 32'h3c0b_abcd;
	_ROM[15] = 32'h0085_6025;
	_ROM[16] = 32'h0003_6826;
	_ROM[17] = 32'h0085_7027;
	_ROM[18] = 32'h000e_7900;
	_ROM[19] = 32'h000e_8102;
	_ROM[20] = 32'h3401_abcd;
	_ROM[21] = 32'h3803_a123;
	_ROM[22] = 32'h0061_2024;
	_ROM[23] = 32'h0061_2824;
	_ROM[24] = 32'h0061_3024;
	_ROM[25] = 32'h0061_3824;

//  sw and lw test
/*
    _ROM[0] = 32'h2001_3fff;
	_ROM[1] = 32'h3402_0020;
	_ROM[2] = 32'hac01_0004;
	_ROM[3] = 32'h0020_1025;
	_ROM[4] = 32'h8c45_0064;
	_ROM[5] = 32'h00a1_3020;
	*/
	//branch test, beq,bne,j,jal,jr,and slt
	/*
	_ROM[0] = 32'h3407_abcd;
	_ROM[1] = 32'h2001_0000;
	_ROM[2] = 32'h2002_0008;
	_ROM[3] = 32'h2003_0000;
	_ROM[4] = 32'h2021_0001;
	_ROM[5] = 32'h0c00_000c;
	_ROM[6] = 32'h20a5_0001;
	_ROM[7] = 32'h1041_0001;
	_ROM[8] = 32'h0800_0004;
	_ROM[9] = 32'h0023_302a;
	_ROM[10] = 32'h14c3_fff5;
	_ROM[11] = 32'h3807_1234;
	_ROM[12] = 32'h0023_1820;
	_ROM[13] = 32'h03e0_0008;
	*/
	// KeyExtent
	/*
	_ROM[0] = 32'h3415010e;
	_ROM[1] = 32'h22b6002b;
	_ROM[2] = 32'h8ea10000;
	_ROM[3] = 32'h22b50001;
	_ROM[4] = 32'h8ea20000;
	_ROM[5] = 32'h22b50001;
	_ROM[6] = 32'h8ea30000;
	_ROM[7] = 32'h22b50001;
	_ROM[8] = 32'h8ea40000;
	_ROM[9] = 32'h34140140;
	_ROM[10] = 32'h0c00001a;
	_ROM[11] = 32'h00000000;
	_ROM[12] = 32'h22b40001;
	_ROM[13] = 32'h00250826;
	_ROM[14] = 32'h00461026;
	_ROM[15] = 32'h00671826;
	_ROM[16] = 32'h00882026;
	_ROM[17] = 32'h22b50001;
	_ROM[18] = 32'haea10000;
	_ROM[19] = 32'h22b50001;
	_ROM[20] = 32'haea20000;
	_ROM[21] = 32'h22b50001;
	_ROM[22] = 32'haea30000;
	_ROM[23] = 32'h22b50001;
	_ROM[24] = 32'haea40000;
	_ROM[25] = 32'h16b6fff0;
	_ROM[26] = 32'h00042e02;
	_ROM[27] = 32'h30a500ff;
	_ROM[28] = 32'h8ca60000;
	_ROM[29] = 32'h00042c02;
	_ROM[30] = 32'h30a500ff;
	_ROM[31] = 32'h8ca70000;
	_ROM[32] = 32'h00042a02;
	_ROM[33] = 32'h30a500ff;
	_ROM[34] = 32'h8ca80000;
	_ROM[35] = 32'h308500ff;
	_ROM[36] = 32'h8ca90000;
	_ROM[37] = 32'h00075600;
	_ROM[38] = 32'h00085c00;
	_ROM[39] = 32'h00086200;
	_ROM[40] = 32'h00ca6825;
	_ROM[41] = 32'h016c7025;
	_ROM[42] = 32'h01ae7825;
	_ROM[43] = 32'h8e900000;
	_ROM[44] = 32'h01f02826;
	_ROM[45] = 32'h03e00008;
	*/
	/*
	initial begin
		$readmemh("E:/Microprocessor/Project/MARS/key_extent.txt",_ROM);
	end
	*/
	/*
	for(i=46;i<1024;i=i+1)begin
		_ROM[i] <= 32'b0;
	end
	*/
end  
endmodule


>>>>>>> 69d3c22 (add new)
